def process_xml(notice, notice_xml):
    """Pull out relevant fields from the xml and add them to the notice"""

    xml_chunk = notice_xml.xpath('//FURINF/P')
    if xml_chunk:
        notice['contact'] = xml_chunk[0].text

    addresses = fetch_addresses(notice_xml)
    if addresses:
        notice['addresses'] = addresses

    sxs = find_section_by_section(notice_xml)
    sxs = build_section_by_section(sxs, notice['cfr_part'],
                                   notice['meta']['start_page'])
    notice['section_by_section'] = sxs

    context = []
    amends = []
    for par in notice_xml.xpath('//AMDPAR'):
        amend_set, context = parse_amdpar(par, context)
        amends.extend(amend_set)
    if amends:
        notice['amendments'] = amends

    return notice
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
     self.assertEqual(1, len(amends))
     self.assertEqual("PUT", amends[0].action)
     self.assertEqual("[title]", amends[0].field)
     self.assertEqual(["1111", "35", "b", "Interp"], amends[0].label)
Example #3
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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(1, len(amends))
     self.assertEqual('PUT', amends[0].action)
     self.assertEqual('[title]', amends[0].field)
     self.assertEqual(['1111', '35', 'b', 'Interp'], amends[0].label)
 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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(1, len(amends))
     self.assertEqual('PUT', amends[0].action)
     self.assertEqual('[title]', amends[0].field)
     self.assertEqual(['1111', '35', 'b', 'Interp'], amends[0].label)
 def test_parse_amdpar_add_field(self):
     text = "Adding introductory text to paragraph (c)"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     amends, _ = diff.parse_amdpar(xml, ['1111', None, '12'])
     self.assertEqual(1, len(amends))
     amd = amends[0]
     self.assertEqual(amd.action, tokens.Verb.PUT)
     self.assertEqual(amd.label, ['1111', '12', 'c'])
     self.assertEqual(amd.field, '[text]')
 def test_parse_amdpar_add_field(self):
     text = "Adding introductory text to paragraph (c)"
     xml = etree.fromstring("<AMDPAR>%s</AMDPAR>" % text)
     amends, _ = diff.parse_amdpar(xml, ["1111", None, "12"])
     self.assertEqual(1, len(amends))
     amd = amends[0]
     self.assertEqual(amd.action, tokens.Verb.PUT)
     self.assertEqual(amd.label, ["1111", "12", "c"])
     self.assertEqual(amd.field, "[text]")
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
     self.assertEqual(1, len(amends))
     amend = amends[0]
     self.assertEqual("POST", amend.action)
     self.assertEqual(["1111", "A", "Interp", "3"], amend.label)
Example #8
0
 def test_parse_amdpar_add_field(self):
     text = "Adding introductory text to paragraph (c)"
     xml = etree.fromstring('<AMDPAR>%s</AMDPAR>' % text)
     amends, _ = diff.parse_amdpar(xml, ['1111', None, '12'])
     self.assertEqual(1, len(amends))
     amd = amends[0]
     self.assertEqual(amd.action, tokens.Verb.PUT)
     self.assertEqual(amd.label, ['1111', '12', 'c'])
     self.assertEqual(amd.field, '[text]')
Example #9
0
def process_amendments(notice, notice_xml):
    """ Process the changes to the regulation that are expressed in the notice.
    """
    amends = []
    notice_changes = changes.NoticeChanges()

    amdpars_by_parent = []
    for par in notice_xml.xpath('//AMDPAR'):
        parent = par.getparent()
        exists = filter(lambda aXp: aXp.parent == parent, amdpars_by_parent)
        if exists:
            exists[0].append(par)
        else:
            amdpars_by_parent.append(AmdparByParent(parent, par))

    for aXp in amdpars_by_parent:
        amended_labels = []
        designate_labels, other_labels = [], []
        context = [aXp.parent.get('PART') or notice['cfr_part']]
        for par in aXp.amdpars:
            als, context = parse_amdpar(par, context)
            amended_labels.extend(als)

        for al in amended_labels:
            if isinstance(al, DesignateAmendment):
                subpart_changes = process_designate_subpart(al)
                if subpart_changes:
                    notice_changes.update(subpart_changes)
                designate_labels.append(al)
            elif new_subpart_added(al, notice['cfr_part']):
                notice_changes.update(process_new_subpart(notice, al, par))
                designate_labels.append(al)
            else:
                other_labels.append(al)

        create_xmlless_changes(other_labels, notice_changes)

        section_xml = find_section(par)
        if section_xml is not None:
            for section in reg_text.build_from_section(
                    notice['cfr_part'], section_xml):
                create_xml_changes(other_labels, section, notice_changes)

        for appendix in parse_appendix_changes(other_labels,
                                               notice['cfr_part'], aXp.parent):
            create_xml_changes(other_labels, appendix, notice_changes)

        interp = parse_interp_changes(other_labels, notice['cfr_part'],
                                      aXp.parent)
        if interp:
            create_xml_changes(other_labels, interp, notice_changes)

        amends.extend(designate_labels)
        amends.extend(other_labels)
    if amends:
        notice['amendments'] = amends
        notice['changes'] = notice_changes.changes
Example #10
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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(1, len(amends))
     amend = amends[0]
     self.assertEqual('POST', amend.action)
     self.assertEqual(['1111', 'A', 'Interp', '3'], amend.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(1, len(amends))
     amend = amends[0]
     self.assertEqual('POST', amend.action)
     self.assertEqual(['1111', 'A', 'Interp', '3'], amend.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
     self.assertEqual(2, len(amends))
     a, b = amends
     self.assertEqual("POST", a.action)
     self.assertEqual(["1111", "12", "c", "3", "ix", "A", "Interp"], a.label)
     self.assertEqual("POST", b.action)
     self.assertEqual(["1111", "12", "c", "3", "ix", "B", "Interp"], b.label)
 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>')
     amends, _ = diff.parse_amdpar(xml, [])
     self.assertEqual(1, len(amends))
     self.assertEqual(amends[0].action, tokens.Verb.POST)
     self.assertEqual(amends[0].label, ['479', '90a'])
     self.assertEqual(amends[0].original_label, '479-Subjgrp:ERtToF-90a')
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
     self.assertEqual(2, len(amends))
     a, b = amends
     self.assertEqual("POST", a.action)
     self.assertEqual(["1111", "12", "a", "Interp"], a.label)
     self.assertEqual("POST", b.action)
     self.assertEqual(["1111", "12", "a", "Interp", "3"], b.label)
Example #15
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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(2, len(amends))
     a, b = amends
     self.assertEqual('POST', a.action)
     self.assertEqual(['1111', '12', 'a', 'Interp'], a.label)
     self.assertEqual('POST', b.action)
     self.assertEqual(['1111', '12', 'a', 'Interp', '3'], b.label)
Example #16
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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(2, len(amends))
     delete, add = amends
     self.assertEqual('DELETE', delete.action)
     self.assertEqual(['1111', '51', 'b', 'Interp', '1'], delete.label)
     self.assertEqual('POST', add.action)
     self.assertEqual(['1111', '51', 'b', '1', 'Interp', '2'], add.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(2, len(amends))
     delete, add = amends
     self.assertEqual('DELETE', delete.action)
     self.assertEqual(['1111', '51', 'b', 'Interp', '1'], delete.label)
     self.assertEqual('POST', add.action)
     self.assertEqual(['1111', '51', 'b', '1', 'Interp', '2'], add.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111"])
     self.assertEqual(1, len(amends))
     self.assertEqual("POST", amends[0].action)
     self.assertEqual(["999", "3", "b", "Interp", "1", "iv"], amends[0].label)
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
     self.assertEqual(2, len(amends))
     delete, add = amends
     self.assertEqual("DELETE", delete.action)
     self.assertEqual(["1111", "51", "b", "Interp", "1"], delete.label)
     self.assertEqual("POST", add.action)
     self.assertEqual(["1111", "51", "b", "1", "Interp", "2"], add.label)
Example #20
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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(2, len(amends))
     a, b = amends
     self.assertEqual('POST', a.action)
     self.assertEqual(['1111', '12', 'c', '3', 'ix', 'A', 'Interp'],
                      a.label)
     self.assertEqual('POST', b.action)
     self.assertEqual(['1111', '12', 'c', '3', 'ix', 'B', 'Interp'],
                      b.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
     self.assertEqual(4, len(amends))
     for amd in amends:
         self.assertEqual("POST", amd.action)
     amd35b1, amd35b1_1, amd35b1_2, amd35b1_3 = amends
     self.assertEqual(["1111", "35", "b", "1", "Interp"], amd35b1.label)
     self.assertEqual(["1111", "35", "b", "1", "Interp", "1"], amd35b1_1.label)
     self.assertEqual(["1111", "35", "b", "1", "Interp", "2"], amd35b1_2.label)
     self.assertEqual(["1111", "35", "b", "1", "Interp", "3"], amd35b1_3.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ['1111'])
     self.assertEqual(1, len(amends))
     self.assertEqual('POST', amends[0].action)
     self.assertEqual(['999', '3', 'b', 'Interp', '1', 'iv'],
                      amends[0].label)
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations", "2", "(a)"])
     self.assertEqual(4, len(amends))
     self.assertEqual(["1111", "2", "a", "Interp", "3", "ii"], amends[0].label)
     self.assertEqual(["1111", "2", "a", "Interp", "3", "iii"], amends[1].label)
     self.assertEqual(["1111", "2", "a", "Interp", "4"], amends[2].label)
     self.assertEqual(["1111", "2", "a", "Interp", "10"], amends[3].label)
     for amend in amends:
         self.assertEqual(amend.action, "PUT")
Example #24
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)
     amends, _ = diff.parse_amdpar(xml, ['1111'])
     self.assertEqual(1, len(amends))
     self.assertEqual('POST', amends[0].action)
     self.assertEqual(['999', '3', 'b', 'Interp', '1', 'iv'],
                      amends[0].label)
 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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(2, len(amends))
     a, b = amends
     self.assertEqual('POST', a.action)
     self.assertEqual(['1111', '12', 'c', '3', 'ix', 'A', 'Interp'],
                      a.label)
     self.assertEqual('POST', b.action)
     self.assertEqual(['1111', '12', 'c', '3', 'ix', 'B', 'Interp'],
                      b.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(2, len(amends))
     a, b = amends
     self.assertEqual('POST', a.action)
     self.assertEqual(['1111', '12', 'a', 'Interp'],
                      a.label)
     self.assertEqual('POST', b.action)
     self.assertEqual(['1111', '12', 'a', 'Interp', '3'],
                      b.label)
 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)
     amends, _ = diff.parse_amdpar(xml, [])
     self.assertEqual(1, len(amends))
     self.assertEqual(amends[0].action, tokens.Verb.POST)
     self.assertEqual(3, len(amends[0].label))
     self.assertEqual(['478', '11'], amends[0].label[:2])
     # Paragraph has a hash
     self.assertTrue(re.match(r'p\d{4}\d+', amends[0].label[2]))
Example #28
0
def process_amendments(notice, notice_xml):
    """Process changes to the regulation that are expressed in the notice."""
    all_amends = []     # will be added to the notice
    cfr_part = notice['cfr_parts'][0]
    notice_changes = changes.NoticeChanges()

    # process amendments in batches, based on their parent XML
    for amdparent in notice_xml.xpath('//AMDPAR/..'):
        context = [amdparent.get('PART') or cfr_part]
        amendments_by_section = defaultdict(list)
        normal_amends = []  # amendments not moving or adding a subpart
        for amdpar in amdparent.xpath('.//AMDPAR'):
            amendments, context = parse_amdpar(amdpar, context)
            section_xml = find_section(amdpar)
            for amendment in amendments:
                all_amends.append(amendment)
                if isinstance(amendment, DesignateAmendment):
                    subpart_changes = process_designate_subpart(amendment)
                    if subpart_changes:
                        notice_changes.update(subpart_changes)
                elif new_subpart_added(amendment):
                    notice_changes.update(process_new_subpart(
                        notice, amendment, amdpar))
                elif section_xml is None:
                    normal_amends.append(amendment)
                else:
                    normal_amends.append(amendment)
                    amendments_by_section[section_xml].append(amendment)

        cfr_part = context[0]   # carry the part through to the next amdparent
        create_xmlless_changes(normal_amends, notice_changes)
        # Process amendments relating to a specific section in batches, too
        for section_xml, related_amends in amendments_by_section.items():
            for section in reg_text.build_from_section(cfr_part, section_xml):
                create_xml_changes(related_amends, section, notice_changes)

        for appendix in parse_appendix_changes(normal_amends, cfr_part,
                                               amdparent):
            create_xml_changes(normal_amends, appendix, notice_changes)

        interp = parse_interp_changes(normal_amends, cfr_part, amdparent)
        if interp:
            create_xml_changes(normal_amends, interp, notice_changes)

    if all_amends:
        notice['amendments'] = all_amends
        notice['changes'] = notice_changes.changes

    return notice
Example #29
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)
     amends, _ = diff.parse_amdpar(xml,
                                   ['1111', 'Interpretations', '2', '(a)'])
     self.assertEqual(4, len(amends))
     self.assertEqual(['1111', '2', 'a', 'Interp', '3', 'ii'],
                      amends[0].label)
     self.assertEqual(['1111', '2', 'a', 'Interp', '3', 'iii'],
                      amends[1].label)
     self.assertEqual(['1111', '2', 'a', 'Interp', '4'], amends[2].label)
     self.assertEqual(['1111', '2', 'a', 'Interp', '10'], amends[3].label)
     for amend in amends:
         self.assertEqual(amend.action, 'PUT')
 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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(4, len(amends))
     for amd in amends:
         self.assertEqual('POST', amd.action)
     amd35b1, amd35b1_1, amd35b1_2, amd35b1_3 = amends
     self.assertEqual(['1111', '35', 'b', '1', 'Interp'], amd35b1.label)
     self.assertEqual(['1111', '35', 'b', '1', 'Interp', '1'],
                      amd35b1_1.label)
     self.assertEqual(['1111', '35', 'b', '1', 'Interp', '2'],
                      amd35b1_2.label)
     self.assertEqual(['1111', '35', 'b', '1', 'Interp', '3'],
                      amd35b1_3.label)
Example #31
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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(4, len(amends))
     for amd in amends:
         self.assertEqual('POST', amd.action)
     amd35b1, amd35b1_1, amd35b1_2, amd35b1_3 = amends
     self.assertEqual(['1111', '35', 'b', '1', 'Interp'], amd35b1.label)
     self.assertEqual(['1111', '35', 'b', '1', 'Interp', '1'],
                      amd35b1_1.label)
     self.assertEqual(['1111', '35', 'b', '1', 'Interp', '2'],
                      amd35b1_2.label)
     self.assertEqual(['1111', '35', 'b', '1', 'Interp', '3'],
                      amd35b1_3.label)
 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)
     amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
     self.assertEqual(4, len(amends))
     a1, a2del, a3, a2add = amends
     self.assertEqual(a1.action, tokens.Verb.PUT)
     self.assertEqual(a1.label, ["1111", "22", "a", "Interp", "1"])
     self.assertEqual(a2del.action, tokens.Verb.DELETE)
     self.assertEqual(a2del.label, ["1111", "22", "a", "Interp", "2"])
     self.assertEqual(a3.action, tokens.Verb.POST)
     self.assertEqual(a3.label, ["1111", "22", "a", "Interp", "3"])
     self.assertEqual(a2add.action, tokens.Verb.POST)
     self.assertEqual(a2add.label, ["1111", "22", "a", "Interp", "2"])
Example #33
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)
     amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
     self.assertEqual(4, len(amends))
     a1, a2del, a3, a2add = amends
     self.assertEqual(a1.action, tokens.Verb.PUT)
     self.assertEqual(a1.label, ['1111', '22', 'a', 'Interp', '1'])
     self.assertEqual(a2del.action, tokens.Verb.DELETE)
     self.assertEqual(a2del.label, ['1111', '22', 'a', 'Interp', '2'])
     self.assertEqual(a3.action, tokens.Verb.POST)
     self.assertEqual(a3.label, ['1111', '22', 'a', 'Interp', '3'])
     self.assertEqual(a2add.action, tokens.Verb.POST)
     self.assertEqual(a2add.label, ['1111', '22', 'a', 'Interp', '2'])
 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)
     amends, _ = diff.parse_amdpar(xml,
                                   ['1111', 'Interpretations', '2', '(a)'])
     self.assertEqual(4, len(amends))
     self.assertEqual(['1111', '2', 'a', 'Interp', '3', 'ii'],
                      amends[0].label)
     self.assertEqual(['1111', '2', 'a', 'Interp', '3', 'iii'],
                      amends[1].label)
     self.assertEqual(['1111', '2', 'a', 'Interp', '4'],
                      amends[2].label)
     self.assertEqual(['1111', '2', 'a', 'Interp', '10'],
                      amends[3].label)
     for amend in amends:
         self.assertEqual(amend.action, 'PUT')
    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)
        amends, _ = diff.parse_amdpar(xml, ["1111", "Interpretations"])
        self.assertEqual(5, len(amends))
        a11, a12, a1i, a1i1, a1i2 = amends
        self.assertEqual("DELETE", a11.action)
        self.assertEqual(["1111", "45", "a", "1", "Interp", "1"], a11.label)
        self.assertEqual("DELETE", a12.action)
        self.assertEqual(["1111", "45", "a", "1", "Interp", "2"], a12.label)

        self.assertEqual("POST", a1i.action)
        self.assertEqual(["1111", "45", "a", "1", "i", "Interp"], a1i.label)
        self.assertEqual("POST", a1i1.action)
        self.assertEqual(["1111", "45", "a", "1", "i", "Interp", "1"], a1i1.label)
        self.assertEqual("POST", a1i2.action)
        self.assertEqual(["1111", "45", "a", "1", "i", "Interp", "2"], a1i2.label)
Example #36
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)
        amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
        self.assertEqual(5, len(amends))
        a11, a12, a1i, a1i1, a1i2 = amends
        self.assertEqual('DELETE', a11.action)
        self.assertEqual(['1111', '45', 'a', '1', 'Interp', '1'], a11.label)
        self.assertEqual('DELETE', a12.action)
        self.assertEqual(['1111', '45', 'a', '1', 'Interp', '2'], a12.label)

        self.assertEqual('POST', a1i.action)
        self.assertEqual(['1111', '45', 'a', '1', 'i', 'Interp'], a1i.label)
        self.assertEqual('POST', a1i1.action)
        self.assertEqual(['1111', '45', 'a', '1', 'i', 'Interp', '1'],
                         a1i1.label)
        self.assertEqual('POST', a1i2.action)
        self.assertEqual(['1111', '45', 'a', '1', 'i', 'Interp', '2'],
                         a1i2.label)
    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)
        amends, _ = diff.parse_amdpar(xml, ['1111', 'Interpretations'])
        self.assertEqual(5, len(amends))
        a11, a12, a1i, a1i1, a1i2 = amends
        self.assertEqual('DELETE', a11.action)
        self.assertEqual(['1111', '45', 'a', '1', 'Interp', '1'], a11.label)
        self.assertEqual('DELETE', a12.action)
        self.assertEqual(['1111', '45', 'a', '1', 'Interp', '2'], a12.label)

        self.assertEqual('POST', a1i.action)
        self.assertEqual(['1111', '45', 'a', '1', 'i', 'Interp'], a1i.label)
        self.assertEqual('POST', a1i1.action)
        self.assertEqual(['1111', '45', 'a', '1', 'i', 'Interp', '1'],
                         a1i1.label)
        self.assertEqual('POST', a1i2.action)
        self.assertEqual(['1111', '45', 'a', '1', 'i', 'Interp', '2'],
                         a1i2.label)
Example #38
0
def process_amendments(notice, notice_xml):
    """ Process the changes to the regulation that are expressed in the notice.
    """
    amends = []
    notice_changes = changes.NoticeChanges()

    amdpars_by_parent = []
    for par in notice_xml.xpath('//AMDPAR'):
        parent = par.getparent()
        exists = filter(lambda aXp: aXp.parent == parent, amdpars_by_parent)
        if exists:
            exists[0].append(par)
        else:
            amdpars_by_parent.append(AmdparByParent(parent, par))

    default_cfr_part = notice['cfr_parts'][0]
    for aXp in amdpars_by_parent:
        amended_labels = []
        designate_labels, other_labels = [], []
        context = [aXp.parent.get('PART') or default_cfr_part]
        for par in aXp.amdpars:
            als, context = parse_amdpar(par, context)
            amended_labels.extend(als)

        labels_by_part = defaultdict(list)
        for al in amended_labels:
            if isinstance(al, DesignateAmendment):
                subpart_changes = process_designate_subpart(al)
                if subpart_changes:
                    notice_changes.update(subpart_changes)
                designate_labels.append(al)
            elif new_subpart_added(al):
                notice_changes.update(process_new_subpart(notice, al, par))
                designate_labels.append(al)
            else:
                other_labels.append(al)
                labels_by_part[al.label[0]].append(al)

        create_xmlless_changes(other_labels, notice_changes)

        for cfr_part, rel_labels in labels_by_part.iteritems():
            section_xml = find_section(par)
            if section_xml is not None:
                for section in reg_text.build_from_section(
                        cfr_part, section_xml):
                    create_xml_changes(rel_labels, section, notice_changes)

            for appendix in parse_appendix_changes(rel_labels, cfr_part,
                                                   aXp.parent):
                create_xml_changes(rel_labels, appendix, notice_changes)

            interp = parse_interp_changes(rel_labels, cfr_part, aXp.parent)
            if interp:
                create_xml_changes(rel_labels, interp, notice_changes)

        amends.extend(designate_labels)
        amends.extend(other_labels)

        if other_labels:  # Carry cfr_part through amendments
            default_cfr_part = other_labels[-1].label[0]

    if amends:
        notice['amendments'] = amends
        notice['changes'] = notice_changes.changes
Example #39
0
def process_amendments(notice, notice_xml):
    """ Process the changes to the regulation that are expressed in the notice.
    """
    amends = []
    notice_changes = changes.NoticeChanges()

    amdpars_by_parent = []
    for par in notice_xml.xpath('//AMDPAR'):
        parent = par.getparent()
        exists = filter(lambda aXp: aXp.parent == parent, amdpars_by_parent)
        if exists:
            exists[0].append(par)
        else:
            amdpars_by_parent.append(AmdparByParent(parent, par))

    default_cfr_part = notice['cfr_part']
    for aXp in amdpars_by_parent:
        amended_labels = []
        designate_labels, other_labels = [], []
        context = [default_cfr_part]
        for par in aXp.amdpars:
            als, context = parse_amdpar(par, context)
            amended_labels.extend(als)

            labels_by_part = defaultdict(list)
            for al in amended_labels:
                if isinstance(al, DesignateAmendment):
                    subpart_changes = process_designate_subpart(al)
                    if subpart_changes:
                        notice_changes.update(subpart_changes)
                    designate_labels.append(al)
                elif new_subpart_added(al):
                    notice_changes.update(process_new_subpart(notice, al, par))
                    designate_labels.append(al)
                else:
                    other_labels.append(al)
                    labels_by_part[al.label[0]].append(al)

            create_xmlless_changes(other_labels, notice_changes)

            # for cfr_part, rel_labels in labels_by_part.iteritems():
            labels_for_part = {
                part: labels
                for part, labels in labels_by_part.iteritems()
                if part == default_cfr_part
            }
            print(labels_for_part)
            for cfr_part, rel_labels in labels_for_part.iteritems():
                section_xml = find_section(par)
                if section_xml is not None:
                    subparts = aXp.parent.xpath('.//SUBPART/HD')
                    if subparts:
                        subpart_label = [
                            cfr_part, 'Subpart', subparts[0].text[8:9]
                        ]
                    else:
                        subpart_label = None

                    for section in reg_text.build_from_section(
                            cfr_part, section_xml):
                        create_xml_changes(rel_labels, section, notice_changes,
                                           subpart_label)

                for appendix in parse_appendix_changes(rel_labels, cfr_part,
                                                       aXp.parent):
                    create_xml_changes(rel_labels, appendix, notice_changes)

                interp = parse_interp_changes(rel_labels, cfr_part, aXp.parent)
                if interp:
                    create_xml_changes(rel_labels, interp, notice_changes)

            amends.extend(designate_labels)
            amends.extend(other_labels)

            # if other_labels:    # Carry cfr_part through amendments
            #    default_cfr_part = other_labels[-1].label[0]

    if amends:
        notice['amendments'] = amends
        notice['changes'] = notice_changes.changes
    elif notice['document_number'] in settings.REISSUANCES:
        notice['changes'] = {
            default_cfr_part: [{
                'action': 'PUT',
                'node': reg_text.build_tree(notice_xml)
            }]
        }
Example #40
0
def process_amendments(notice, notice_xml):
    """ Process the changes to the regulation that are expressed in the notice.
    """
    amends = []
    notice_changes = changes.NoticeChanges()

    amdpars_by_parent = []
    for par in notice_xml.xpath('//AMDPAR'):
        parent = par.getparent()
        exists = filter(lambda aXp: aXp.parent == parent, amdpars_by_parent)
        if exists:
            exists[0].append(par)
        else:
            amdpars_by_parent.append(AmdparByParent(parent, par))

    default_cfr_part = notice['cfr_parts'][0]
    for aXp in amdpars_by_parent:
        amended_labels = []
        designate_labels, other_labels = [], []
        context = [aXp.parent.get('PART') or default_cfr_part]
        for par in aXp.amdpars:
            als, context = parse_amdpar(par, context)
            amended_labels.extend(als)

            labels_by_part = defaultdict(list)
            for al in amended_labels:
                if isinstance(al, DesignateAmendment):
                    subpart_changes = process_designate_subpart(al)
                    if subpart_changes:
                        notice_changes.update(subpart_changes)
                    designate_labels.append(al)
                elif new_subpart_added(al):
                    notice_changes.update(process_new_subpart(notice, al, par))
                    designate_labels.append(al)
                else:
                    other_labels.append(al)
                    labels_by_part[al.label[0]].append(al)

            create_xmlless_changes(other_labels, notice_changes)

            for cfr_part, rel_labels in labels_by_part.iteritems():
                section_xml = find_section(par)
                if section_xml is not None:
                    subparts = aXp.parent.xpath('.//SUBPART/HD')
                    if subparts:
                        subpart_label = [cfr_part, 'Subpart',
                                         subparts[0].text[8:9]]
                    else:
                        subpart_label = None

                    for section in reg_text.build_from_section(cfr_part,
                                                               section_xml):
                        create_xml_changes(rel_labels, section, notice_changes,
                                           subpart_label)

                for appendix in parse_appendix_changes(rel_labels, cfr_part,
                                                       aXp.parent):
                    create_xml_changes(rel_labels, appendix, notice_changes)

                interp = parse_interp_changes(rel_labels, cfr_part, aXp.parent)
                if interp:
                    create_xml_changes(rel_labels, interp, notice_changes)

            amends.extend(designate_labels)
            amends.extend(other_labels)

            if other_labels:    # Carry cfr_part through amendments
                default_cfr_part = other_labels[-1].label[0]

    if amends:
        notice['amendments'] = amends
        notice['changes'] = notice_changes.changes
    elif notice['document_number'] in settings.REISSUANCES:
        notice['changes'] = {
            default_cfr_part: [{
                'action': 'PUT',
                'node': reg_text.build_tree(notice_xml)
            }]
        }