ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/ns_dev/Python/NinoCode/Active_prgs/Redgrave/NS_MasterAttorneyList.py
Revision: 982
Committed: Tue Feb 24 22:43:35 2026 UTC (4 weeks, 3 days ago) by nino.borges
Content type: text/x-python
File size: 28183 byte(s)
Log Message:
Added support to run a check on the MAL ID numbers.  I dont use these but members of the team does, so I added this as a check.

File Contents

# User Rev Content
1 nino.borges 954 """
2    
3     NS_MasterAttorneyList
4    
5     Created by:
6     Emanuel Borges
7     11.01.2025
8    
9     A library for the creation and management of the Norfolk Southern MAL.
10    
11     """
12    
13     import os, uuid, pickle, re
14     from dataclasses import dataclass, field, fields
15     from typing import List, Tuple, Optional
16     from collections import namedtuple
17     from win32com.client import Dispatch
18    
19    
20 nino.borges 982 version = "2.1"
21 nino.borges 954
22     @dataclass
23     class Person:
24     first_name: Optional[str] = None
25     last_name: Optional[str] = None
26     alt_first_names: Optional[str] = None
27     alt_surnames: Optional[str] = None
28     ## TODO: Make these email addresses lists instead of strings
29     work_email_addresses: Optional[str] = None
30     raw_email_addresses: Optional[str] = None
31     _id: uuid.UUID = field(default_factory=uuid.uuid4)
32     is_attorney: Optional[str] = None
33     split_role_date_range: Optional[str] = None
34     middle_initial: Optional[str] = None
35     company: Optional[str] = None
36     category: Optional[str] = None
37     job_title: Optional[str] = None
38     full_name_preferred: Optional[str] = None
39     vendor_normalized_name: Optional[str] = None
40     user_id: Optional[str] = None
41     full_name_overide: Optional[str] = None
42     ## Only gather unique_attorney_row_number from the attorney and split role attorney tabs. NEVER from Non-Attorneys.
43     unique_attorney_row_number:Optional[str] = None
44     ## Will be saving this as a list of tuple pairs (startdate,enddate). Allowing None for now but may update this to forcing an empty list, to avoid mutable default issues.
45     dates_as_counsel:Optional[List[Tuple[str,str]]] = None
46    
47     def __post_init__(self):
48     """Convert all string fields to uppercase."""
49     if self.first_name:
50     self.first_name = self.first_name.strip().upper()
51     if self.alt_first_names:
52     self.alt_first_names = self.alt_first_names.strip().upper()
53     if self.alt_surnames:
54     self.alt_surnames = self.alt_surnames.strip().upper()
55     if self.last_name:
56     self.last_name = self.last_name.strip().upper()
57     if self.work_email_addresses:
58     self.work_email_addresses = self.work_email_addresses.strip().upper()
59    
60     if self.raw_email_addresses:
61     self.raw_email_addresses = self.raw_email_addresses.strip().upper()
62     if self.is_attorney:
63     self.is_attorney = self.is_attorney.strip().upper()
64     if self.split_role_date_range:
65     self.split_role_date_range = self.split_role_date_range.strip().upper()
66     if self.middle_initial:
67     self.middle_initial = self.middle_initial.strip().upper()
68     if self.company:
69     self.company = self.company.strip().upper()
70     if self.category:
71     self.category = self.category.strip().upper()
72     if self.job_title:
73     self.job_title = self.job_title.strip().upper()
74     if self.full_name_preferred:
75     self.full_name_preferred = self.full_name_preferred.strip().upper()
76     if self.vendor_normalized_name:
77     self.vendor_normalized_name = self.vendor_normalized_name.strip().upper()
78     if self.user_id:
79     self.user_id = self.user_id.strip().upper()
80    
81    
82     @dataclass
83     class PeopleList:
84     people: List[Person] = field(default_factory=list)
85    
86     def add_person(self, person: Person):
87     self.people.append(person)
88     #print(f"Added person: {person}")
89    
90    
91     def search_by_email(self, emailAddress:str) -> Optional[Person]:
92     """Returns the first matching emailAddress value. Assumes emailAddresses are unique"""
93     for person in self.people:
94     if person.work_email_addresses:
95     #print(person.work_email_addresses)
96     personEmailAddresses = person.work_email_addresses.split(";\n")
97     personEmailAddresses = [x.strip() for x in personEmailAddresses]
98     if emailAddress in personEmailAddresses:
99     #if person.work_email_addresses == emailAddress:
100     return person
101     ## elif person.alt_work_email_addresses == emailAddress:
102     ## return person
103     return None
104    
105     def search_by_login_id(self, loginID:str) -> Optional[Person]:
106     """Returns the first matching login user id value. Assumes login user ids are unique"""
107     for person in self.people:
108     if person.user_id:
109     personLoginIds = person.user_id.split(";\n")
110     personLoginIds = [x.strip() for x in personLoginIds]
111     if loginID in personLoginIds:
112     return person
113     return None
114    
115     def search_by_unique_attorney_row_number(self,uniqueAttorneyRowNumber:str) -> Optional[Person]:
116     """Returns the first matching uniqueAttorneyRowNumber value. Assumes uniqueAttorneyRowNumbers are unique"""
117     for person in self.people:
118     if person.unique_attorney_row_number == uniqueAttorneyRowNumber:
119     return person
120     return None
121    
122     def search_by_id(self, idNumber):
123     """Returns the first matching idNumber value. Must be in format UUID('7414f78c-8289-4c9f-bd49-a5aaac35545f')."""
124     for person in self.people:
125     if person._id == idNumber:
126     return person
127     return None
128    
129     def return_list_of_matching_values(self,fieldName, value:str):
130     """Returns a full list of items where value is found in fieldName"""
131     matchingPeopleList = []
132     for person in self.people:
133     personVals = getattr(person,fieldName)
134     if personVals:
135     personVals = personVals.split(";\n")
136     personVals = [x.strip() for x in personVals]
137     if value in personVals:
138     matchingPeopleList.append(person)
139     return matchingPeopleList
140    
141     def list_people(self):
142     for person in self.people:
143     print(person)
144    
145     def update_full_Name_overide(self, emailAddress:str, fullNameOverideValue) -> Optional[Person]:
146     valueUpdated = False
147     for person in self.people:
148     if person.work_email_addresses == emailAddress.upper():
149     person.full_name_overide = fullNameOverideValue.upper()
150     valueUpdated = True
151     ## Give a quik warning as you add the override value into the database if the last name differs.
152     if "," in fullNameOverideValue:
153     lastName = fullNameOverideValue.split(",")[0]
154     else:
155     lastName = fullNameOverideValue.split(" ")[-1]
156     if lastName.upper() == person.last_name:
157     pass
158     else:
159     print(f"WARNING: Overide last name value {lastName.upper()} does not match {person.last_name}.")
160     if valueUpdated == False:
161     print(f"WARNING: No email address match for {emailAddress} found.")
162    
163     def return_person_all_name_variations(self, person):
164     ## TODO: Fix this to support multiple alt first names and multiple surnames.
165     """This will take a matched person and return a large list of all of the possible full name variations"""
166 nino.borges 955 #last = person.last_name.strip() if person.last_name else None
167     lasts = [person.last_name.strip() if person.last_name else None]
168     if person.alt_surnames:
169     lasts += person.alt_surnames.split(";\n")
170    
171 nino.borges 954 firsts = [person.first_name.strip() if person.first_name else None]
172     if person.alt_first_names:
173     #firsts.append(person.alt_first_names.strip())
174     firsts += person.alt_first_names.split(";\n")
175    
176     middle = person.middle_initial.replace(".","").strip() if person.middle_initial else None
177    
178     combos = set() ## Using a set here to avoid dupes.
179    
180 nino.borges 955 for last in lasts:
181     for first in firsts:
182     ## Some basic combinations
183     combos.add(f"{first} {last}")
184     combos.add(f"{last} {first}")
185     combos.add(f"{last}, {first}")
186 nino.borges 954
187 nino.borges 955 ## Include middle initial variations if it exists
188     if middle:
189     combos.add(f"{first} {middle} {last}")
190     combos.add(f"{last} {first} {middle}")
191     combos.add(f"{last}, {first} {middle}")
192     combos.add(f"{first} {middle}. {last}")
193     combos.add(f"{last} {first} {middle}.")
194     combos.add(f"{last}, {first} {middle}.")
195 nino.borges 954
196     fNamePrefered = person.full_name_preferred
197     if fNamePrefered:
198     fNamePrefered = fNamePrefered.split(";\n")
199     fNamePrefered = [x.strip() for x in fNamePrefered]
200     combos.update(fNamePrefered)
201     if person.vendor_normalized_name:
202     combos.add(person.vendor_normalized_name.strip())
203     ## Want to add the vendor version of the name without the ESQ here.
204     combos.add(person.vendor_normalized_name.upper().replace("(ESQ.)","").strip())
205     return list(combos)
206    
207     class NS_MasterAttorneyList(object):
208     """A class for building and performing functions against the NS Master Attorney List."""
209     version = '0.01.0'
210    
211    
212     def __init__(self, masterAttorneyListFileName,fullNameOveridesFileName = False, forceNewPklFile = False, Encoding = 'UTF8'):
213     """Assumes the MAL is a spreadsheet (for now).MAL gets saved to a pkl file for performance reasons. pkl will be used unless forceNewPklFile is set to true"""
214     pklFileName = os.path.splitext(masterAttorneyListFileName)[0] + ".pkl"
215    
216     print("Initializing data structures...")
217     if forceNewPklFile:
218     print("Creating MAL structure...")
219     self.malPeopleList = PeopleList()
220     self.__IngestMALSpreadsheet(masterAttorneyListFileName)
221     print("MAL structure created.")
222     if fullNameOveridesFileName:
223     print("Loading full name overide values...")
224     self.__LoadFullNameOverideValues(fullNameOveridesFileName)
225     print("Full name overide values loaded.")
226     print("Creating pickle backup...")
227     self.__SaveMalToPkl(pklFileName)
228     print("Pickle backup created.")
229     else:
230     if os.path.exists(pklFileName):
231     print("Loading MAL structure from pickle file...")
232     self.malPeopleList = self.__LoadMalFromPkl(pklFileName)
233     print("MAL structure loaded.")
234     else:
235     print("Pickle file doesnt exist.")
236     print("Creating MAL structure...")
237     self.malPeopleList = PeopleList()
238     self.__IngestMALSpreadsheet(masterAttorneyListFileName)
239     print("MAL structure created.")
240     if fullNameOveridesFileName:
241     print("Loading full name overide values...")
242     self.__LoadFullNameOverideValues(fullNameOveridesFileName)
243     print("Full name overide values loaded.")
244     print("Creating pickle backup...")
245     self.__SaveMalToPkl(pklFileName)
246     print("Pickle backup created.")
247    
248    
249     def __IngestMALSpreadsheet(self, masterAttorneyListFileName):
250     """Pseudo-private method which will open an Excel spreadsheet and ingest the values into the peoplelist dataclass."""
251     ## There doenst seem to be a consistent value in the "row" column in the MAL, so setting these parameters here to avoid gap issues.
252    
253     ## excelTabParametersList should always be an ordered list because now order matters.
254 nino.borges 982 excelTabParametersList = [{"tabName":"Attorneys", "beginRowNumber":2, "endRowNumber":215, "beginColNumber":1, "endColNumber":20},
255     {"tabName":"Non-Attorneys", "beginRowNumber":2, "endRowNumber":19, "beginColNumber":1, "endColNumber":20},
256 nino.borges 954 {"tabName":"Split Role Attorneys", "beginRowNumber":2, "endRowNumber":21, "beginColNumber":1, "endColNumber":10}]
257    
258    
259     # spreadsheetFileMappingMatrix = {"First Name":"first_name", "Last Name":"last_name", "Work Email":"work_email_address", "Alt Work Email":"alt_work_email_address", "Is Attorney": "is_attorney",
260     # "Split Role - Attorney Capacity Date Range":"split_role_date_range", " Validated by OC??":"sidley_validated", "Category": "category", "Organization":"organization", "Job Title":"job_title",
261     # "Business Title":"business_title", "Full Name (Preferred)":"full_name_preferred", "Login":"login", "Department (Fine)":"department_fine", "Addressed during CAAG":"addressed_during_caag",
262     # "Last Updated":"last_updated"}
263    
264     xlApp = Dispatch('Excel.Application')
265     xlBook = xlApp.Workbooks.Open(masterAttorneyListFileName)
266    
267     for excelTab in excelTabParametersList:
268     sht = xlBook.Worksheets(excelTab['tabName'])
269     print(f"Ingesting sheet {excelTab['tabName']}.")
270     excelFieldPositionMatrix = {}
271     for col in range (excelTab['beginColNumber'], excelTab['endColNumber'] +1):
272     excelFieldPositionMatrix[sht.Cells(1,col).Value] = col
273     for row in range(excelTab['beginRowNumber'], excelTab['endRowNumber'] +1):
274     #print(row)
275     ## TODO: Refactor the excelTabParametersList later. Didnt realize columns were not consistent.
276     if excelTab['tabName'] == 'Attorneys':
277     self.malPeopleList.add_person(Person(is_attorney = sht.Cells(row,excelFieldPositionMatrix['Is Attorney']).Value,
278     #split_role_date_range = sht.Cells(row,excelFieldPositionMatrix['Split Role - Dates as Counsel']).Value,
279     company = sht.Cells(row,excelFieldPositionMatrix['Company']).Value,
280     category = sht.Cells(row,excelFieldPositionMatrix['Category']).Value,
281     last_name = sht.Cells(row,excelFieldPositionMatrix['Last Name']).Value,
282     first_name = sht.Cells(row,excelFieldPositionMatrix['First Name']).Value,
283     alt_first_names = sht.Cells(row,excelFieldPositionMatrix['Alt First Names']).Value,
284     alt_surnames = sht.Cells(row,excelFieldPositionMatrix['Alt Surnames']).Value,
285     middle_initial = sht.Cells(row,excelFieldPositionMatrix['Middle Initial']).Value,
286     work_email_addresses = sht.Cells(row,excelFieldPositionMatrix['Email Addresses']).Value,
287     #alt_work_email_address = sht.Cells(row,excelFieldPositionMatrix['Alt Work Email']).Value,
288     raw_email_addresses = sht.Cells(row,excelFieldPositionMatrix['EmailAddress RAW']).Value,
289     job_title = sht.Cells(row,excelFieldPositionMatrix['Title']).Value,
290     full_name_preferred = sht.Cells(row,excelFieldPositionMatrix['Full Name (Preferred)']).Value,
291     vendor_normalized_name = sht.Cells(row,excelFieldPositionMatrix['Vendor Normalized Name']).Value,
292     user_id = sht.Cells(row,excelFieldPositionMatrix['UserID']).Value,
293     unique_attorney_row_number = sht.Cells(row,excelFieldPositionMatrix['MAL ID']).Value))
294    
295     elif excelTab['tabName'] == 'Non-Attorneys':
296     ## Make sure to NOT grab the unique attorney row number from here
297     self.malPeopleList.add_person(Person(is_attorney = sht.Cells(row,excelFieldPositionMatrix['Is Attorney']).Value,
298     #split_role_date_range = sht.Cells(row,excelFieldPositionMatrix['Split Role - Dates as Counsel']).Value,
299     company = sht.Cells(row,excelFieldPositionMatrix['Company']).Value,
300     category = sht.Cells(row,excelFieldPositionMatrix['Category']).Value,
301     last_name = sht.Cells(row,excelFieldPositionMatrix['Last Name']).Value,
302     first_name = sht.Cells(row,excelFieldPositionMatrix['First Name']).Value,
303     alt_first_names = sht.Cells(row,excelFieldPositionMatrix['Alt First Names']).Value,
304     alt_surnames = sht.Cells(row,excelFieldPositionMatrix['Alt Surnames']).Value,
305     middle_initial = sht.Cells(row,excelFieldPositionMatrix['Middle Initial']).Value,
306     work_email_addresses = sht.Cells(row,excelFieldPositionMatrix['Email Addresses']).Value,
307     #alt_work_email_address = sht.Cells(row,excelFieldPositionMatrix['Alt Work Email']).Value,
308     raw_email_addresses = sht.Cells(row,excelFieldPositionMatrix['EmailAddress RAW']).Value,
309     job_title = sht.Cells(row,excelFieldPositionMatrix['Title']).Value,
310     full_name_preferred = sht.Cells(row,excelFieldPositionMatrix['Full Name (Preferred)']).Value,
311     vendor_normalized_name = sht.Cells(row,excelFieldPositionMatrix['Vendor Normalized Name']).Value,
312     user_id = sht.Cells(row,excelFieldPositionMatrix['UserID']).Value,
313     unique_attorney_row_number = sht.Cells(row,excelFieldPositionMatrix['MAL ID']).Value))
314     elif excelTab['tabName'] == 'Split Role Attorneys':
315     ## Skip this tab for now.
316     pass
317     ## unique_attorney_row_number = sht.Cells(row,excelFieldPositionMatrix['Attorney Row']).Value
318     ## matchedPerson = self.malPeopleList.search_by_unique_attorney_row_number(unique_attorney_row_number)
319     ## if matchedPerson:
320     ##
321     ## ## dates_as_counsel should always be a two string value tuple (startdate,enddate).
322     ## datesAsCounselValue = sht.Cells(row,excelFieldPositionMatrix['Dates as Counsel']).Value
323     ## datesAsCounselList = []
324     ## ## First get rid of any extra data that is on a new line. Note that they shouldnt be seperating the date ranges by newline.
325     ## datesAsCounselValue = datesAsCounselValue.split("\n")[0]
326     ## ## Next split the ranges correctly by semicolon
327     ## dateRanges = datesAsCounselValue.split(";")
328     ## for dateRange in dateRanges:
329     ## ## Split out the start and end, allowing non-date words. (current, present, etc) however force these to be uppercase.
330     ## counselStartDate, counselEndDate = dateRange.split("-")
331     ## counselStartDate = counselStartDate.upper().strip()
332     ## counselEndDate = counselEndDate.upper().strip()
333     ## datesAsCounselList.append((counselStartDate,counselEndDate))
334     ## matchedPerson.dates_as_counsel = datesAsCounselList
335    
336     else:
337     print(f"ERROR UNKNOWN TAB! {excelTab['tabName']} HAVE NEEDED TAB NAMES CHANGED?")
338    
339    
340     xlBook.Close()
341    
342    
343    
344     def __SaveMalToPkl(self, pklFileName):
345     """Pseudo-private method which will save the current MAL people list object to a pkl file, for performance reasons."""
346     outputFile = open(pklFileName,'wb')
347     pickle.dump(self.malPeopleList,outputFile)
348     outputFile.close()
349    
350     def __LoadMalFromPkl(self, pklFileName):
351     """Pseudo-private method which will load a MAL people list object from a pkl file, for performance reasons."""
352     contents = open(pklFileName, 'rb')
353     obj = pickle.load(contents)
354     contents.close()
355     return obj
356    
357     def __LoadFullNameOverideValues(self, fullNameOveridesFileName):
358     """Pseudo-private method which will update the MAL people list object with the full name overide values."""
359     contents = open(fullNameOveridesFileName).readlines()
360     for line in contents:
361     line = line.replace("\n","")
362     emailAddress,fullNameOverideValue = line.split("|")
363    
364     self.malPeopleList.update_full_Name_overide(emailAddress, fullNameOverideValue)
365    
366     def SmartDedupeSet(self, currentSet):
367     """A method that attempts to do some additional deduplication of the values in a set by lowering all values and deduplicating. Returns a lowered deduplicated set."""
368     newSet = set()
369     for val in currentSet:
370     newSet.add(val.lower())
371     return newSet
372    
373    
374    
375     def RunMalEmailAddressIntegrityCheck(self):
376     """This method performs an integrity check on the MAL by analyzing and looking for duplicate email addresses."""
377     emailTestMatrix = {}
378     altTestMatrix = {}
379     print("Performing MAL email address integrity check...")
380     for i in range(0,len(self.malPeopleList.people)):
381     #altAddr = self.malPeopleList.people[i].alt_work_email_address
382     altAddr = None
383     ## Right now workaddrs are stored as a string that you need to parse to use.
384     workAddrs = self.malPeopleList.people[i].work_email_addresses
385     if altAddr != None:
386     altAddr = altAddr.strip()
387     if altAddr in list(emailTestMatrix.keys()):
388     print(f"ISSUE:{altAddr} is a dupe of an workAddr.")
389     if altAddr in list(altTestMatrix.keys()):
390     print(f"ISSUE:{altAddr} is a dupe!")
391     else:
392     altTestMatrix[altAddr] = 1
393     if workAddrs != None:
394     workAddrs = [w.upper().strip() for w in workAddrs.split(";\n")]
395     for workAddr in workAddrs:
396     workAddr = workAddr.strip()
397     if workAddr in list(altTestMatrix.keys()):
398     print(f"ISSUE:{workAddr} is a dupe of an altAddr.")
399     if workAddr in list(emailTestMatrix.keys()):
400     print(f"ISSUE:{workAddr} is a dupe!")
401     else:
402     emailTestMatrix[workAddr] = 1
403     print("\nEmail address integrity check complete.\n\n")
404    
405    
406     def RunMalLoginIdIntegrityCheck(self):
407     """This method performs an integrity check on the MAL by analyzing and looking for duplicate User Login ID values."""
408     loginIdTestMatrix = {}
409     print("Performing MAL user login ID integrity check...")
410     for i in range(0,len(self.malPeopleList.people)):
411     loginIds = self.malPeopleList.people[i].user_id
412     if loginIds != None:
413     loginIds = [w.upper().strip() for w in loginIds.split(";\n")]
414     for loginId in loginIds:
415     loginId = loginId.strip()
416     if loginId in list(loginIdTestMatrix.keys()):
417     print(f"ISSUE:{loginId} is a dupe!")
418     else:
419     loginIdTestMatrix[loginId] = 1
420     print("\nUser Login ID integrity check complete.\n\n")
421    
422 nino.borges 982
423    
424     def RunUniqueAttorneyRowNumberCheck(self):
425     """Performs an integrity check on the unique_attorney_row_number calues, both for attorney and non-attorney"""
426     attorneyUniqueNumberList = []
427     non_attorneyUniqueNumberList = []
428     print("Performing MAL Unique Attorney Row Number integrity check...")
429     for i in range(0,len(self.malPeopleList.people)):
430     unique_id = self.malPeopleList.people[i].unique_attorney_row_number
431     if unique_id:
432     if self.malPeopleList.people[i].is_attorney == "NO":
433     non_attorneyUniqueNumberList.append(int(unique_id))
434     else:
435     attorneyUniqueNumberList.append(int(unique_id))
436     non_attorneyUniqueNumberList.sort()
437     attorneyUniqueNumberList.sort()
438     print(f"{non_attorneyUniqueNumberList[0]}-{non_attorneyUniqueNumberList[-1]}")
439     print(f"{attorneyUniqueNumberList[0]}-{attorneyUniqueNumberList[-1]}")
440    
441     def analyze_number_list(numbers):
442     if not numbers:
443     return [], []
444     sorted_nums = sorted(numbers)
445     duplicates = []
446     gaps = []
447     previous = sorted_nums[0]
448     for current in sorted_nums[1:]:
449     if current == previous:
450     duplicates.append(current)
451     elif current > previous +1:
452     gaps.extend(range(previous +1, current))
453     previous = current
454     return gaps, duplicates
455    
456    
457     ## Check the attorney values first
458     attorney_gaps, attorney_duplicates = analyze_number_list(attorneyUniqueNumberList)
459     print("\nAttorney Unique Number Check")
460     print ("-" *40)
461     if attorney_gaps:
462     print(f"Gaps found({len(attorney_gaps)}): {attorney_gaps}")
463     else:
464     print("No gaps found.")
465     if attorney_duplicates:
466     print(f"Duplicates Found({len(attorney_duplicates)}): {attorney_duplicates}")
467     else:
468     print("No duplicates found.")
469    
470    
471     ## Check non-attorney values
472     non_attorney_gaps, non_attorney_duplicates = analyze_number_list(non_attorneyUniqueNumberList)
473     print("\nNon-Attorney Unique Number Check")
474     print ("-" *40)
475     if non_attorney_gaps:
476     print(f"Gaps found({len(non_attorney_gaps)}): {non_attorney_gaps}")
477     else:
478     print("No gaps found.")
479     if non_attorney_duplicates:
480     print(f"Duplicates Found({len(non_attorney_duplicates)}): {non_attorney_duplicates}")
481     else:
482     print("No duplicates found.")
483    
484 nino.borges 954 if __name__ == '__main__':
485 nino.borges 982 masterAttorneyListFileName = r"C:\Users\eborges\OneDrive - Redgrave LLP\Documents\Cases\Norfolk Southern\_NS_Current_MAL\RG - NS Cross-Matter Master Attorney List 20260120 (20260120-0136).xlsx"
486 nino.borges 954 nsMal = NS_MasterAttorneyList(masterAttorneyListFileName)
487     test = nsMal.malPeopleList.search_by_email('Catharine.Fletcher@nscorp.com'.upper())
488     nsMal.malPeopleList.return_person_all_name_variations(test)
489     test = nsMal.malPeopleList.search_by_email('mcarr@dmclaw.com'.upper())
490     #test = attMal.malPeopleList.search_by_email('LMENRIQUEZ@DIRECTV.COM')
491     #test = attMal.malPeopleList.return_list_of_matching_values('work_email_addresses','LMENRIQUEZ@DIRECTV.COM')
492     #test = attMal.malPeopleList.search_by_login_id('JS6637')
493     print(test)
494     print(nsMal.malPeopleList.return_person_all_name_variations(test))
495     nsMal.RunMalEmailAddressIntegrityCheck()
496 nino.borges 982 nsMal.RunMalLoginIdIntegrityCheck()
497     nsMal.RunUniqueAttorneyRowNumberCheck()