def test_parse_amdpar_interp_heading(self):
     text = "ii. The heading for 35(b) blah blah is revised."
     xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.PUT(label='1111-Interpretations-35-(b)[title]')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #2
0
def assert_instruction_conversion(instruction_text, initial_label):
    """We have several tests that require creating an AMDPAR with the provided
    instruction_text, parsing, and comparing it to a built set of XML."""
    amdpar = etree.fromstring('<AMDPAR>{0}</AMDPAR>'.format(instruction_text))
    with XMLBuilder('EREGS_INSTRUCTIONS') as expected:
        yield expected
    instructions, _ = amdparser.parse_amdpar(amdpar, initial_label)
    assert etree.tounicode(instructions) == expected.xml_str
예제 #3
0
def assert_instruction_conversion(instruction_text, initial_label):
    """We have several tests that require creating an AMDPAR with the provided
    instruction_text, parsing, and comparing it to a built set of XML."""
    amdpar = etree.fromstring('<AMDPAR>{0}</AMDPAR>'.format(instruction_text))
    with XMLBuilder('EREGS_INSTRUCTIONS') as expected:
        yield expected
    instructions, _ = amdparser.parse_amdpar(amdpar, initial_label)
    assert etree.tounicode(instructions) == expected.xml_str
예제 #4
0
    def test_parse_amdpar_add_field(self):
        text = "Adding introductory text to paragraph (c)"
        xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
        instructions, _ = amdparser.parse_amdpar(xml, ['1111', None, '12'])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.PUT(label='1111-?-12-c[text]')
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #5
0
 def test_parse_amdpar_interp_heading(self):
     text = "ii. The heading for 35(b) blah blah is revised."
     xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.PUT(label='1111-Interpretations-35-(b)[title]')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
    def test_parse_amdpar_add_field(self):
        text = "Adding introductory text to paragraph (c)"
        xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
        instructions, _ = amdparser.parse_amdpar(xml, ['1111', None, '12'])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.PUT(label='1111-?-12-c[text]')
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #7
0
 def test_parse_amdpar_interp_entries(self):
     text = "Entries for 12(c)(3)(ix)(A) and (B) are added."
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-12-(c)(3)(ix)(A)')
         ctx.POST(label='1111-Interpretations-12-(c)(3)(ix)(B)')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #8
0
 def test_parse_amdpar_and_and(self):
     text = "12(a) 'Titles and Paragraphs' and paragraph 3 are added"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-12-(a)')
         ctx.POST(label='1111-Interpretations-12-(a)-3')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #9
0
 def test_parse_amdpar_and_in_tags(self):
     text = "Under <E>Appendix A - Some phrase and another</E>, paragraph "
     text += "3 is added"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-A-()-3')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
 def test_parse_amdpar_and_in_tags(self):
     text = "Under <E>Appendix A - Some phrase and another</E>, paragraph "
     text += "3 is added"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-A-()-3')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
 def test_parse_amdpar_and_and(self):
     text = "12(a) 'Titles and Paragraphs' and paragraph 3 are added"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-12-(a)')
         ctx.POST(label='1111-Interpretations-12-(a)-3')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
 def test_parse_amdpar_interp_entries(self):
     text = "Entries for 12(c)(3)(ix)(A) and (B) are added."
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-12-(c)(3)(ix)(A)')
         ctx.POST(label='1111-Interpretations-12-(c)(3)(ix)(B)')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
    def test_parse_amdpar_subject_group(self):
        xml = etree.fromstring(
            '<AMDPAR>8. Section 479.90a is added to '
            '[subject-group(Exemptions Relating to Transfers of Firearms)] '
            'to read as follows.</AMDPAR>')
        instructions, _ = amdparser.parse_amdpar(xml, [])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.POST(label='479-Subjgrp:ERtToF-90a')
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #14
0
    def test_parse_amdpar_subject_group(self):
        xml = etree.fromstring(
            '<AMDPAR>8. Section 479.90a is added to '
            '[subject-group(Exemptions Relating to Transfers of Firearms)] '
            'to read as follows.</AMDPAR>')
        instructions, _ = amdparser.parse_amdpar(xml, [])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.POST(label='479-Subjgrp:ERtToF-90a')
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #15
0
 def test_parse_amdpar_interp_redesignated(self):
     text = "Paragraph 1 under 51(b) is redesignated as paragraph 2 "
     text += "under subheading 51(b)(1) and revised"
     xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.DELETE(label='1111-Interpretations-51-(b)-1')
         ctx.POST(label='1111-Interpretations-51-(b)(1)-2')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
 def test_parse_amdpar_interp_redesignated(self):
     text = "Paragraph 1 under 51(b) is redesignated as paragraph 2 "
     text += "under subheading 51(b)(1) and revised"
     xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.DELETE(label='1111-Interpretations-51-(b)-1')
         ctx.POST(label='1111-Interpretations-51-(b)(1)-2')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
 def test_parse_amdpar_interp_context(self):
     text = "b. 35(b)(1) Some title and paragraphs 1, 2, and 3 are added."
     xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-35-(b)(1)')
         ctx.POST(label='1111-Interpretations-35-(b)(1)-1')
         ctx.POST(label='1111-Interpretations-35-(b)(1)-2')
         ctx.POST(label='1111-Interpretations-35-(b)(1)-3')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #18
0
 def test_parse_amdpar_interp_context(self):
     text = "b. 35(b)(1) Some title and paragraphs 1, 2, and 3 are added."
     xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.POST(label='1111-Interpretations-35-(b)(1)')
         ctx.POST(label='1111-Interpretations-35-(b)(1)-1')
         ctx.POST(label='1111-Interpretations-35-(b)(1)-2')
         ctx.POST(label='1111-Interpretations-35-(b)(1)-3')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #19
0
    def test_parse_amdpar_interp_phrase(self):
        text = u"In Supplement I to part 999, under"
        text += u'<E T="03">Section 999.3—Header,</E>'
        text += u"under"
        text += u'<E T="03">3(b) Subheader,</E>'
        text += u"new paragraph 1.iv is added:"
        xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
        instructions, _ = amdparser.parse_amdpar(xml, ['1111'])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.POST(label='999-Interpretations-3-(b)-1-iv')
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
    def test_parse_amdpar_interp_phrase(self):
        text = u"In Supplement I to part 999, under"
        text += u'<E T="03">Section 999.3—Header,</E>'
        text += u"under"
        text += u'<E T="03">3(b) Subheader,</E>'
        text += u"new paragraph 1.iv is added:"
        xml = etree.fromstring(u'<AMDPAR>%s</AMDPAR>' % text)
        instructions, _ = amdparser.parse_amdpar(xml, ['1111'])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.POST(label='999-Interpretations-3-(b)-1-iv')
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
    def test_parse_amdpar_newly_redesignated(self):
        text = "Paragraphs 3.ii, 3.iii, 4 and newly redesignated paragraph "
        text += "10 are revised."
        xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.PUT(label='1111-Interpretations-2-(a)-3-ii')
            ctx.PUT(label='1111-Interpretations-2-(a)-3-iii')
            ctx.PUT(label='1111-Interpretations-2-(a)-4')
            ctx.PUT(label='1111-Interpretations-2-(a)-10')

        instructions, _ = amdparser.parse_amdpar(
            xml, ['1111', 'Interpretations', '2', '(a)'])
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
 def test_parse_amdpar_verbs_ands(self):
     text = "Under 45(a)(1) Title, paragraphs 1 and 2 are removed, and "
     text += "45(a)(1)(i) Deeper Title and paragraphs 1 and 2 are added"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.DELETE(label='1111-Interpretations-45-(a)(1)-1')
         ctx.DELETE(label='1111-Interpretations-45-(a)(1)-2')
         ctx.POST(label='1111-Interpretations-45-(a)(1)(i)')
         ctx.POST(label='1111-Interpretations-45-(a)(1)(i)-1')
         ctx.POST(label='1111-Interpretations-45-(a)(1)(i)-2')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #23
0
    def test_parse_amdpar_definition(self):
        """We should correctly deduce which paragraphs are being updated, even
        when they are identified by definition alone"""
        text = ("Section 478.11 is amended by adding a definition for the "
                u"term “Nonimmigrant visa” in alphabetical order to read as "
                "follows:")
        xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
        instructions, _ = amdparser.parse_amdpar(xml, [])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.POST(label='478-?-11-p{}'.format(
                hash_for_paragraph("Nonimmigrant visa")))
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
 def test_parse_amdpar_moved_then_modified(self):
     text = "Under Paragraph 22(a), paragraph 1 is revised, paragraph "
     text += "2 is redesignated as paragraph 3 and revised, and new "
     text += "paragraph 2 is added."
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.PUT(label='1111-Interpretations-22-(a)-1')
         ctx.DELETE(label='1111-Interpretations-22-(a)-2')
         ctx.POST(label='1111-Interpretations-22-(a)-3')
         ctx.POST(label='1111-Interpretations-22-(a)-2')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #25
0
 def test_parse_amdpar_moved_then_modified(self):
     text = "Under Paragraph 22(a), paragraph 1 is revised, paragraph "
     text += "2 is redesignated as paragraph 3 and revised, and new "
     text += "paragraph 2 is added."
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.PUT(label='1111-Interpretations-22-(a)-1')
         ctx.DELETE(label='1111-Interpretations-22-(a)-2')
         ctx.POST(label='1111-Interpretations-22-(a)-3')
         ctx.POST(label='1111-Interpretations-22-(a)-2')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
    def test_parse_amdpar_definition(self):
        """We should correctly deduce which paragraphs are being updated, even
        when they are identified by definition alone"""
        text = ("Section 478.11 is amended by adding a definition for the "
                u"term “Nonimmigrant visa” in alphabetical order to read as "
                "follows:")
        xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
        instructions, _ = amdparser.parse_amdpar(xml, [])

        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.POST(label='478-?-11-p{}'.format(hash_for_paragraph(
                "Nonimmigrant visa")))
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #27
0
 def test_parse_amdpar_verbs_ands(self):
     text = "Under 45(a)(1) Title, paragraphs 1 and 2 are removed, and "
     text += "45(a)(1)(i) Deeper Title and paragraphs 1 and 2 are added"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     instructions, _ = amdparser.parse_amdpar(xml,
                                              ['1111', 'Interpretations'])
     with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
         ctx.DELETE(label='1111-Interpretations-45-(a)(1)-1')
         ctx.DELETE(label='1111-Interpretations-45-(a)(1)-2')
         ctx.POST(label='1111-Interpretations-45-(a)(1)(i)')
         ctx.POST(label='1111-Interpretations-45-(a)(1)(i)-1')
         ctx.POST(label='1111-Interpretations-45-(a)(1)(i)-2')
     self.assertEqual(etree.tostring(instructions), ctx.xml_str)
예제 #28
0
    def test_parse_amdpar_newly_redesignated(self):
        text = "Paragraphs 3.ii, 3.iii, 4 and newly redesignated paragraph "
        text += "10 are revised."
        xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
        with XMLBuilder('EREGS_INSTRUCTIONS') as ctx:
            ctx.PUT(label='1111-Interpretations-2-(a)-3-ii')
            ctx.PUT(label='1111-Interpretations-2-(a)-3-iii')
            ctx.PUT(label='1111-Interpretations-2-(a)-4')
            ctx.PUT(label='1111-Interpretations-2-(a)-10')

        instructions, _ = amdparser.parse_amdpar(
            xml, ['1111', 'Interpretations', '2', '(a)'])
        self.assertEqual(etree.tostring(instructions), ctx.xml_str)
    def transform(self, xml):
        has_part = xml.xpath('//*[AMDPAR and @PART]')
        context = ['0']
        if has_part:
            context = [has_part[0].get('PART')]
        elif xml.xpath('//AMDPAR'):
            logger.warning('Could not find any PART designators.')

        for amdparent in xml.xpath(self.AMDPARENT_XPATH):
            # Always start with only the CFR part
            context = [amdparent.get('PART') or context[0]]
            for amdpar in amdparent.xpath('.//AMDPAR'):
                instructions, context = parse_amdpar(amdpar, context)
                amdpar.append(instructions)
                instructions.set(
                    'final_context',
                    '-'.join('?' if l is None else l for l in context))
예제 #30
0
    def transform(self, xml):
        has_part = xml.xpath('//*[AMDPAR and @PART]')
        context = ['0']
        if has_part:
            context = [has_part[0].get('PART')]
        elif xml.xpath('//AMDPAR'):
            logger.warning('Could not find any PART designators.')

        for amdparent in xml.xpath(self.AMDPARENT_XPATH):
            # Always start with only the CFR part
            context = [amdparent.get('PART') or context[0]]
            for amdpar in amdparent.xpath('.//AMDPAR'):
                instructions, context = parse_amdpar(amdpar, context)
                amdpar.append(instructions)
                instructions.set(
                    'final_context',
                    '-'.join('?' if l is None else l for l in context))
def preprocess_amdpars(xml):
    """Modify the AMDPAR tag to contain an <EREGS_INSTRUCTIONS> element. This
    element contains an interpretation of the AMDPAR, as viewed as a sequence
    of actions for how to modify the CFR. Do _not_ modify any existing
    EREGS_INSTRUCTIONS (they've been manually created)"""
    has_part = xml.xpath('//*[AMDPAR and @PART]')
    context = ['0']
    if has_part:
        context = [has_part[0].get('PART')]
    elif xml.xpath('//AMDPAR'):
        logger.warning('Could not find any PART designators.')

    for amdparent in xml.xpath(_AMDPARENT_XPATH):
        # Always start with only the CFR part
        context = [amdparent.get('PART') or context[0]]
        for amdpar in amdparent.xpath('.//AMDPAR'):
            instructions, context = parse_amdpar(amdpar, context)
            amdpar.append(instructions)
            instructions.set('final_context', uncertain_label(context))
예제 #32
0
def preprocess_amdpars(xml):
    """Modify the AMDPAR tag to contain an <EREGS_INSTRUCTIONS> element. This
    element contains an interpretation of the AMDPAR, as viewed as a sequence
    of actions for how to modify the CFR. Do _not_ modify any existing
    EREGS_INSTRUCTIONS (they've been manually created)"""
    has_part = xml.xpath('//*[AMDPAR and @PART]')
    context = ['0']
    if has_part:
        context = [has_part[0].get('PART')]
    elif xml.xpath('//AMDPAR'):
        logger.warning('Could not find any PART designators.')

    for amdparent in xml.xpath(_AMDPARENT_XPATH):
        # Always start with only the CFR part
        context = [amdparent.get('PART') or context[0]]
        for amdpar in amdparent.xpath('.//AMDPAR'):
            instructions, context = parse_amdpar(amdpar, context)
            amdpar.append(instructions)
            instructions.set('final_context', uncertain_label(context))