Пример #1
0
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()
Пример #2
0
    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")
Пример #3
0
    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)
Пример #4
0
    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")
Пример #5
0
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
Пример #6
0
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()
Пример #7
0
    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)
Пример #8
0
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 {}
Пример #9
0
    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],
            )
Пример #10
0
 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"])
Пример #11
0
 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'])
Пример #12
0
 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'])
Пример #13
0
 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"])
Пример #14
0
class PacerPossibleCaseNumbersTest(unittest.TestCase):

    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 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 test_filtering_by_office_number(self):
        """Can we filter by office number?"""
        d = self.report.data(office_number='1')
        self.assertEqual('1000068', d['pacer_case_id'])

    def test_filtering_by_civil_or_criminal(self):
        """Can we filter by civil or criminal?"""
        d = self.report.data(docket_number_letters='cv')
        self.assertEqual('977547', d['pacer_case_id'])

    def test_filtering_by_office_and_civil_criminal(self):
        """Can we filter by multiple variables?"""
        d = self.report.data(
            office_number='2',
            docket_number_letters='cr',
        )
        self.assertEqual('977548', d['pacer_case_id'])

    def test_filtering_by_case_name(self):
        d = self.report.data(case_name='Willy Wonka')
        self.assertEqual('977547', d['pacer_case_id'])

    def test_filtering_by_office_and_case_name(self):
        d = self.report.data(office_number='2', case_name="Willy Wonka")
        self.assertEqual('977547', d['pacer_case_id'])

    def test_choosing_the_lowest_sequentially(self):
        """When the ids are sequential, can we pick the lowest one?"""
        d = self.report.data(office_number='2')
        self.assertEqual('977547', d['pacer_case_id'])

    def test_cannot_make_choice_because_not_sequential_ids(self):
        """When the remaining nodes only have IDs that aren't sequential, do we
        give up and throw an error?
        """
        with self.assertRaises(ParsingException):
            _ = self.report.data(office_number='3')

    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'])

    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'])
Пример #15
0
class PacerPossibleCaseNumbersTest(unittest.TestCase):
    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 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, "rb") 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 test_filtering_by_office_number(self):
        """Can we filter by office number?"""
        d = self.report.data(office_number="1")
        self.assertEqual("1000068", d["pacer_case_id"])

    def test_filtering_by_civil_or_criminal(self):
        """Can we filter by civil or criminal?"""
        d = self.report.data(docket_number_letters="cv")
        self.assertEqual("977547", d["pacer_case_id"])

    def test_filtering_by_office_and_civil_criminal(self):
        """Can we filter by multiple variables?"""
        d = self.report.data(
            office_number="2",
            docket_number_letters="cr",
        )
        self.assertEqual("977548", d["pacer_case_id"])

    def test_filtering_by_case_name(self):
        d = self.report.data(case_name="Willy Wonka")
        self.assertEqual("977547", d["pacer_case_id"])

    def test_filtering_by_office_and_case_name(self):
        d = self.report.data(office_number="2", case_name="Willy Wonka")
        self.assertEqual("977547", d["pacer_case_id"])

    def test_choosing_the_lowest_sequentially(self):
        """When the ids are sequential, can we pick the lowest one?"""
        d = self.report.data(office_number="2")
        self.assertEqual("977547", d["pacer_case_id"])

    def test_cannot_make_choice_because_not_sequential_ids(self):
        """When the remaining nodes only have IDs that aren't sequential, do we
        give up and throw an error?
        """
        with self.assertRaises(ParsingException):
            _ = self.report.data(office_number="3")

    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"])

    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"])