def get_pacer_case_id_for_idb_row(self, pk, session): """Populate the pacer_case_id field in the FJC IDB table for an item in the IDB table """ logger.info("Getting pacer_case_id for IDB item with pk %s" % pk) item = FjcIntegratedDatabase.objects.get(pk=pk) pcn = PossibleCaseNumberApi(map_cl_to_pacer_id(item.district_id), session) pcn.query(item.docket_number) params = { 'office_number': item.office if item.office else None, } if item.plaintiff or item.defendant: params['case_name'] = '%s v. %s' % (item.plaintiff, item.defendant) if item.dataset_source in [CR_2017, CR_OLD]: if item.multidistrict_litigation_docket_number: params['docket_number_letters'] = 'md' else: params['docket_number_letters'] = 'cr' elif item.dataset_source in [CV_2017, CV_OLD]: params['docket_number_letters'] = 'cv' try: d = pcn.data(**params) except ParsingException: # Hack. Storing the error in here will bite us later. item.pacer_case_id = "Error" else: if d is not None: item.pacer_case_id = d['pacer_case_id'] item.case_name = d['title'] item.save()
def test_parsing_results(self): """Can we do a simple query and parse?""" paths = [] path_root = os.path.join(TESTS_ROOT, "examples", "pacer", "possible_case_numbers") for root, dirnames, filenames in os.walk(path_root): for filename in fnmatch.filter(filenames, '*.xml'): paths.append(os.path.join(root, filename)) paths.sort() path_max_len = max(len(path) for path in paths) + 2 for i, path in enumerate(paths): sys.stdout.write("%s. Doing %s" % (i, path.ljust(path_max_len))) dirname, filename = os.path.split(path) filename_sans_ext = filename.split('.')[0] json_path = os.path.join(dirname, '%s.json' % filename_sans_ext) report = PossibleCaseNumberApi('anything') with open(path, 'r') as f: report._parse_text(f.read().decode('utf-8')) data = report.data(case_name=filename_sans_ext) if os.path.exists(json_path): with open(json_path) as f: j = json.load(f) self.assertEqual(j, data) else: # If no json file, data should be None. self.assertIsNone( data, msg="No json file detected and response is not None. " "Either create a json file for this test or make sure " "you get back valid results.") sys.stdout.write("✓\n")
def setUp(self): xml = """ <request number="16-01152"> <case number="1:16-cr-1152" id="1000068" title="1:16-cr-01152-JZB USA v. Abuarar (closed 01/26/2017)" sortable="1:2016-cr-01152"/> <!-- For use with office and case name filtering --> <case number="2:16-cv-1152" id="977547" title="2:16-cv-01152-JJT Willy Wonka v. Charlie (closed 06/09/2017)" sortable="2:2016-cv-01152-JJT"/> <case number="2:16-cr-1152" id="977548" title="2:16-cv-01152-JJT Armes v. Hot Pizzas LLC (closed 06/09/2017)" sortable="2:2016-cv-01152-JJT"/> <!-- Not non-sequential id values --> <case number="3:16-cr-1152" id="1" title="3:16-cr-01152-JJT Willy Wonka v. Charlie (closed 06/09/2017)" sortable="3:2016-cr-01152-JJT"/> <case number="3:16-cr-1152" id="3" title="3:16-cv-01152-JJT Armes v. Hot Pizzas LLC (closed 06/09/2017)" sortable="3:2016-cv-01152-JJT"/> </request> """ self.report = PossibleCaseNumberApi("anything") self.report._parse_text(xml)
def get_pacer_case_id_and_title(self, docket_number, court_id, cookies, case_name=None, office_number=None, docket_number_letters=None, ): """Get the pacer_case_id and title values for a district court docket. Use heuristics to disambiguate the results. office_number and docket_number_letters are only needed when they are not already part of the docket_number passed in. Multiple parameters are needed here to allow flexibility when using this API. Some sources, like the IDB, have this data all separated out, so it helps not to try to recreate docket numbers from data that comes all pulled apart. :param docket_number: The docket number to look up. This is a flexible field that accepts a variety of docket number styles. :param court_id: The CourtListener court ID for the docket number :param cookies: A requests.cookies.RequestsCookieJar with the cookies of a logged-in PACER user. :param case_name: The case name to use for disambiguation :param office_number: The number (or letter) where the case took place. Typically, this is in the beginning of the docket number before the colon. This will be used for disambiguation. If you passed it as part of the docket number, it is not needed here. :param docket_number_letters: These are the letters, (cv, cr, md, etc.) that may appear in a docket number. This is used for disambiguation. If you passed these letters in the docket number, you do not need to pass these letters again here. :return: The dict formed by the PossibleCaseNumberApi lookup if a good value is identified, else None. The dict takes the form of: { u'docket_number': force_unicode(node.xpath('./@number')[0]), u'pacer_case_id': force_unicode(node.xpath('./@id')[0]), u'title': force_unicode(node.xpath('./@title')[0]), } """ logger.info("Getting pacer_case_id for docket_number %s in court %s", docket_number, court_id) s = PacerSession(cookies=cookies) report = PossibleCaseNumberApi(map_cl_to_pacer_id(court_id), s) try: report.query(docket_number) except requests.RequestException as exc: logger.warning("RequestException while running possible case number " "query. Trying again if retries not exceeded: %s.%s", court_id, docket_number) if self.request.retries == self.max_retries: self.request.callbacks = None return None raise self.retry(exc=exc) try: return report.data(case_name=case_name, office_number=office_number, docket_number_letters=docket_number_letters) except ParsingException: return None
def get_pacer_case_id_for_idb_row(self, pk, session): """Populate the pacer_case_id field for an item in the IDB table""" logger.info("Getting pacer_case_id for IDB item with pk %s" % pk) item = FjcIntegratedDatabase.objects.get(pk=pk) pcn = PossibleCaseNumberApi(map_cl_to_pacer_id(item.district_id), session) pcn.query(item.docket_number) d = pcn.data(case_name='%s v. %s' % (item.plaintiff, item.defendant)) if d is not None: item.pacer_case_id = d['pacer_case_id'] item.case_name = d['title'] else: # Hack. Storing the error in here will bite us later. item.pacer_case_id = "Error" item.save()
def fetch_pacer_case_id_and_title(s, fq, court_id): """Use PACER's hidden API to learn the pacer_case_id of a case :param s: A PacerSession object to use :param fq: The PacerFetchQueue object to use :param court_id: The CL ID of the court :return: A dict of the new information or an empty dict if it fails """ if (fq.docket_id and not fq.docket.pacer_case_id) or fq.docket_number: # We lack the pacer_case_id either on the docket or from the # submission. Look it up. docket_number = fq.docket_number or getattr(fq.docket, "docket_number", None) report = PossibleCaseNumberApi(map_cl_to_pacer_id(court_id), s) report.query(docket_number) return report.data() return {}
def get_pacer_case_ids(self): """Find PACER Case IDs from iQuery :return: None """ q = Query() db = TinyDB("db/master.json") fjc_table = db.table("fjc") for row in fjc_table.search((q.PACER_CASE_ID == "")): report = PossibleCaseNumberApi(row["COURT"], self.s) report.query(row["DOCKET_NO"]) data = report.data(office_number=row["OFFICE"], docket_number_letters="cv") fjc_table.update( {"PACER_CASE_ID": data["pacer_case_id"], "TITLE": data["title"]}, doc_ids=[row.doc_id], )
def test_pick_sequentially_by_defendant_number(self): """Does this work properly when we pick by sequential defendant number?""" xml = """ <request number='1700355'> <case number='2:15-cr-158' id='284385' title='2:15-cr-00158-JAM USA v. Beaver et al (closed 12/12/2017)' defendant='0' sortable='2:2015-cr-00158-JAM'/> <case number='2:15-cr-158-1' id='285846' title='2:15-cr-00158-JAM-1 Bryce Beaver (closed 05/24/2016)' defendant='1' sortable='2:2015-cr-00158'/> <case number='2:15-cr-158-2' id='284386' title='2:15-cr-00158-JAM-2 Charles Beaver (closed 10/18/2016)' defendant='2' sortable='2:2015-cr-00158'/> <case number='2:15-cr-158-3' id='284858' title='2:15-cr-00158-JAM-3 Sharod Gibbons (closed 12/12/2017)' defendant='3' sortable='2:2015-cr-00158'/> </request> """ report = PossibleCaseNumberApi("anything") report._parse_text(xml) d = report.data() self.assertEqual("284385", d["pacer_case_id"])
def test_no_case_name_with_sequential_ids(self): """Does this work properly when we don't have a case name, but we do have the office number, criminal vs. civil info, and sequential ids? """ xml = """ <request number='1700355'> <case number='3:17-cv-355' id='307135' title='3:17-cv-00355-MEJ Emeziem v. JPMorgan Chase Bank, N.A. (closed 11/09/2017)' sortable='3:2017-cv-00355-MEJ'/> <case number='4:17-cr-355' id='313707' title='4:17-cr-00355-YGR USA v. Kim et al' defendant='0' sortable='4:2017-cr-00355-YGR'/> <case number='4:17-cr-355-1' id='313708' title='4:17-cr-00355-YGR-1 Man Young Kim' defendant='1' sortable='4:2017-cr-00355'/> <case number='4:17-cr-355-2' id='313709' title='4:17-cr-00355-YGR-2 Kyong Ja Kim' defendant='2' sortable='4:2017-cr-00355'/> </request> """ report = PossibleCaseNumberApi("anything") report._parse_text(xml) d = report.data(office_number="4", docket_number_letters="cr") self.assertEqual("313707", d["pacer_case_id"])