def test_process_amendments_section(self): xml = u""" <REGTEXT PART="105" TITLE="12"> <AMDPAR> 3. In § 105.1, revise paragraph (b) to read as follows: </AMDPAR> <SECTION> <SECTNO>§ 105.1</SECTNO> <SUBJECT>Purpose.</SUBJECT> <STARS/> <P>(b) This part carries out.</P> </SECTION> </REGTEXT> """ notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['105'], 'cfr_part': '105'} build.process_amendments(notice, notice_xml) self.assertEqual(notice['changes'].keys(), ['105-1-b']) changes = notice['changes']['105-1-b'][0] self.assertEqual(changes['action'], 'PUT') self.assertTrue( changes['node'].text.startswith(u'(b) This part carries out.'))
def test_process_amendments_multiple_in_same_parent(self): xml = u""" <REGTEXT PART="105" TITLE="12"> <AMDPAR> 1. In § 105.1, revise paragraph (b) to read as follows: </AMDPAR> <AMDPAR>2. Also, revise paragraph (c):</AMDPAR> <SECTION> <SECTNO>§ 105.1</SECTNO> <SUBJECT>Purpose.</SUBJECT> <STARS/> <P>(b) This part carries out.</P> <P>(c) More stuff</P> </SECTION> </REGTEXT>""" notice_xml = etree.fromstring(xml) notice = {"cfr_parts": ["105"]} build.process_amendments(notice, notice_xml) self.assertEqual(notice["changes"].keys(), ["105-1-b", "105-1-c"]) changes = notice["changes"]["105-1-b"][0] self.assertEqual(changes["action"], "PUT") self.assertEqual(changes["node"]["text"].strip(), u"(b) This part carries out.") changes = notice["changes"]["105-1-c"][0] self.assertEqual(changes["action"], "PUT") self.assertTrue(changes["node"]["text"].strip(), u"(c) More stuff")
def test_process_amendments_restart_new_section(self): with XMLBuilder("ROOT") as ctx: with ctx.REGTEXT(PART="104", TITLE="12"): ctx.AMDPAR("1. In Supplement I to Part 104, comment " "22(a) is added") ctx.P("Content") with ctx.REGTEXT(PART="105", TITLE="12"): ctx.AMDPAR(u"3. In § 105.1, revise paragraph (b) to read as " u"follows:") with ctx.SECTION(): ctx.SECTNO(u"§ 105.1") ctx.SUBJECT("Purpose.") ctx.STARS() ctx.P("(b) This part carries out.") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, ctx.xml) self.assertEqual(2, len(notice['amendments'])) c22a, b = notice['amendments'] self.assertEqual(c22a.action, 'POST') self.assertEqual(b.action, 'PUT') self.assertEqual(c22a.label, ['104', '22', 'a', 'Interp']) self.assertEqual(b.label, ['105', '1', 'b'])
def test_process_amendments_mix_regs(self): """Some notices apply to multiple regs. For now, just ignore the sections not associated with the reg we're focused on""" with XMLBuilder("ROOT") as ctx: with ctx.REGTEXT(PART="105", TITLE="12"): ctx.AMDPAR(u"3. In § 105.1, revise paragraph (a) to read as " u"follows:") with ctx.SECTION(): ctx.SECTNO(u"§ 105.1") ctx.SUBJECT("105Purpose.") ctx.P("(a) 105Content") with ctx.REGTEXT(PART="106", TITLE="12"): ctx.AMDPAR(u"3. In § 106.3, revise paragraph (b) to read as " u"follows:") with ctx.SECTION(): ctx.SECTNO(u"§ 106.3") ctx.SUBJECT("106Purpose.") ctx.P("(b) Content") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['105', '106']} build.process_amendments(notice, ctx.xml) self.assertEqual(2, len(notice['changes'])) self.assertTrue('105-1-a' in notice['changes']) self.assertTrue('106-3-b' in notice['changes'])
def test_process_amendments_mix_regs(self): """Some notices apply to multiple regs. For now, just ignore the sections not associated with the reg we're focused on""" with self.tree.builder("ROOT") as root: with root.REGTEXT(PART="105", TITLE="12") as regtext: regtext.AMDPAR(u"3. In § 105.1, revise paragraph (a) to read " "as follows:") with regtext.SECTION() as section: section.SECTNO(u"§ 105.1") section.SUBJECT("105Purpose.") section.P("(a) 105Content") with root.REGTEXT(PART="106", TITLE="12") as regtext: regtext.AMDPAR(u"3. In § 106.3, revise paragraph (b) to read " "as follows:") with regtext.SECTION() as section: section.SECTNO(u"§ 106.3") section.SUBJECT("106Purpose.") section.P("(b) Content") notice = {'cfr_parts': ['105', '106']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual(2, len(notice['changes'])) self.assertTrue('105-1-a' in notice['changes']) self.assertTrue('106-3-b' in notice['changes'])
def test_process_amendments_multiple_in_same_parent(self): with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx: ctx.AMDPAR(u"1. In § 105.1, revise paragraph (b) to read as " u"follows:") ctx.AMDPAR("2. Also, revise paragraph (c):") with ctx.SECTION(): ctx.SECTNO(u"§ 105.1") ctx.SUBJECT("Purpose.") ctx.STARS() ctx.P("(b) This part carries out.") ctx.P("(c) More stuff") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, ctx.xml) self.assertItemsEqual(notice['changes'].keys(), ['105-1-b', '105-1-c']) changes = notice['changes']['105-1-b'][0] self.assertEqual(changes['action'], 'PUT') self.assertEqual(changes['node']['text'].strip(), u'(b) This part carries out.') changes = notice['changes']['105-1-c'][0] self.assertEqual(changes['action'], 'PUT') self.assertTrue(changes['node']['text'].strip(), u'(c) More stuff')
def test_multiple_changes(self): """ A notice can have two modifications to a paragraph. """ xml = u""" <ROOT> <REGTEXT PART="106" TITLE="12"> <AMDPAR> 2. Designate §§ 106.1 through 106.3 as subpart A under the heading. </AMDPAR> </REGTEXT> <REGTEXT PART="106" TITLE="12"> <AMDPAR> 3. In § 106.2, revise the introductory text to read as follows: </AMDPAR> <SECTION> <SECTNO>§ 106.2</SECTNO> <SUBJECT> Definitions </SUBJECT> <P> Except as otherwise provided, the following apply. </P> </SECTION> </REGTEXT> </ROOT> """ notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['106']} build.process_amendments(notice, notice_xml) self.assertEqual(2, len(notice['changes']['106-2']))
def test_process_amendments_section(self): xml = u""" <REGTEXT PART="105" TITLE="12"> <AMDPAR> 3. In § 105.1, revise paragraph (b) to read as follows: </AMDPAR> <SECTION> <SECTNO>§ 105.1</SECTNO> <SUBJECT>Purpose.</SUBJECT> <STARS/> <P>(b) This part carries out.</P> </SECTION> </REGTEXT> """ notice_xml = etree.fromstring(xml) notice = {'cfr_part': '105'} build.process_amendments(notice, notice_xml) self.assertEqual(notice['changes'].keys(), ['105-1-b']) changes = notice['changes']['105-1-b'][0] self.assertEqual(changes['action'], 'PUT') self.assertTrue(changes['node']['text'].startswith( u'(b) This part carries out.'))
def test_process_amendments_subpart(self): notice = {'cfr_parts': ['105']} build.process_amendments(notice, self.new_subpart_xml()) self.assertTrue('105-Subpart-B' in notice['changes'].keys()) self.assertTrue('105-30-a' in notice['changes'].keys()) self.assertTrue('105-30' in notice['changes'].keys())
def test_process_amendments_multiple_in_same_parent(self): xml = u""" <REGTEXT PART="105" TITLE="12"> <AMDPAR> 1. In § 105.1, revise paragraph (b) to read as follows: </AMDPAR> <AMDPAR>2. Also, revise paragraph (c):</AMDPAR> <SECTION> <SECTNO>§ 105.1</SECTNO> <SUBJECT>Purpose.</SUBJECT> <STARS/> <P>(b) This part carries out.</P> <P>(c) More stuff</P> </SECTION> </REGTEXT>""" notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, notice_xml) self.assertEqual(notice['changes'].keys(), ['105-1-b', '105-1-c']) changes = notice['changes']['105-1-b'][0] self.assertEqual(changes['action'], 'PUT') self.assertEqual(changes['node']['text'].strip(), u'(b) This part carries out.') changes = notice['changes']['105-1-c'][0] self.assertEqual(changes['action'], 'PUT') self.assertTrue(changes['node']['text'].strip(), u'(c) More stuff')
def test_process_amendments_restart_new_section(self): xml = u""" <ROOT> <REGTEXT PART="104" TITLE="12"> <AMDPAR> 1. In Supplement I to Part 104, comment 22(a) is added </AMDPAR> <P>Content</P> </REGTEXT> <REGTEXT PART="105" TITLE="12"> <AMDPAR> 3. In § 105.1, revise paragraph (b) to read as follows: </AMDPAR> <SECTION> <SECTNO>§ 105.1</SECTNO> <SUBJECT>Purpose.</SUBJECT> <STARS/> <P>(b) This part carries out.</P> </SECTION> </REGTEXT> </ROOT>""" notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, notice_xml) self.assertEqual(2, len(notice['amendments'])) c22a, b = notice['amendments'] self.assertEqual(c22a.action, 'POST') self.assertEqual(b.action, 'PUT') self.assertEqual(c22a.label, ['104', '22', 'a', 'Interp']) self.assertEqual(b.label, ['105', '1', 'b'])
def test_process_amendments_mix_regs(self): """Some notices apply to multiple regs. For now, just ignore the sections not associated with the reg we're focused on""" xml = u""" <ROOT> <REGTEXT PART="105" TITLE="12"> <AMDPAR> 3. In § 105.1, revise paragraph (a) to read as follows: </AMDPAR> <SECTION> <SECTNO>§ 105.1</SECTNO> <SUBJECT>105Purpose.</SUBJECT> <P>(a) 105Content</P> </SECTION> </REGTEXT> <REGTEXT PART="106" TITLE="12"> <AMDPAR> 3. In § 106.3, revise paragraph (b) to read as follows: </AMDPAR> <SECTION> <SECTNO>§ 106.3</SECTNO> <SUBJECT>106Purpose.</SUBJECT> <P>(b) Content</P> </SECTION> </REGTEXT> </ROOT> """ notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['105', '106']} build.process_amendments(notice, notice_xml) self.assertEqual(2, len(notice['changes'])) self.assertTrue('105-1-a' in notice['changes']) self.assertTrue('106-3-b' in notice['changes'])
def test_process_amendments_multiple_in_same_parent(self): with self.tree.builder("REGTEXT", PART="105", TITLE="12") as regtext: regtext.AMDPAR(u"1. In § 105.1, revise paragraph (b) to read as " "follows:") regtext.AMDPAR("2. Also, revise paragraph (c):") with regtext.SECTION() as section: section.SECTNO(u"§ 105.1") section.SUBJECT("Purpose.") section.STARS() section.P("(b) This part carries out.") section.P("(c) More stuff") notice = {'cfr_parts': ['105']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual(notice['changes'].keys(), ['105-1-b', '105-1-c']) changes = notice['changes']['105-1-b'][0] self.assertEqual(changes['action'], 'PUT') self.assertEqual(changes['node']['text'].strip(), u'(b) This part carries out.') changes = notice['changes']['105-1-c'][0] self.assertEqual(changes['action'], 'PUT') self.assertTrue(changes['node']['text'].strip(), u'(c) More stuff')
def test_process_amendments_context(self): """Context should carry over between REGTEXTs""" xml = u""" <ROOT> <REGTEXT TITLE="12"> <AMDPAR> 3. In § 106.1, revise paragraph (a) to read as follows: </AMDPAR> </REGTEXT> <REGTEXT TITLE="12"> <AMDPAR> 3. Add appendix C </AMDPAR> </REGTEXT> </ROOT> """ notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['105', '106']} build.process_amendments(notice, notice_xml) self.assertEqual(2, len(notice['amendments'])) amd1, amd2 = notice['amendments'] self.assertEqual(['106', '1', 'a'], amd1.label) self.assertEqual(['106', 'C'], amd2.label)
def test_process_amendments_subpart(self): xml = self.new_subpart_xml() notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, notice_xml) self.assertTrue('105-Subpart-B' in notice['changes'].keys()) self.assertTrue('105-30-a' in notice['changes'].keys()) self.assertTrue('105-30' in notice['changes'].keys())
def test_process_amendments_subpart(self): xml = self.new_subpart_xml() notice_xml = etree.fromstring(xml) notice = {"cfr_parts": ["105"]} build.process_amendments(notice, notice_xml) self.assertTrue("105-Subpart-B" in notice["changes"].keys()) self.assertTrue("105-30-a" in notice["changes"].keys()) self.assertTrue("105-30" in notice["changes"].keys())
def test_process_amendments_no_nodes(self): with self.tree.builder("ROOT") as root: with root.REGTEXT(PART="104", TITLE="12") as regtext: regtext.AMDPAR(u"1. In § 104.13, paragraph (b) is removed") notice = {'cfr_parts': ['104']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual(1, len(notice['amendments'])) delete = notice['amendments'][0] self.assertEqual(delete.action, 'DELETE') self.assertEqual(delete.label, ['104', '13', 'b'])
def test_process_amendments_no_nodes(self): with XMLBuilder("ROOT") as ctx: with ctx.REGTEXT(PART="104", TITLE="12"): ctx.AMDPAR(u"1. In § 104.13, paragraph (b) is removed") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['104']} build.process_amendments(notice, ctx.xml) self.assertEqual(1, len(notice['amendments'])) delete = notice['amendments'][0] self.assertEqual(delete.action, 'DELETE') self.assertEqual(delete.label, ['104', '13', 'b'])
def test_introductory_text(self): """ Sometimes notices change just the introductory text of a paragraph (instead of changing the entire paragraph tree). """ with XMLBuilder("REGTEXT", PART="106", TITLE="12") as ctx: ctx.AMDPAR(u"3. In § 106.2, revise the introductory text to read " u"as follows:") with ctx.SECTION(): ctx.SECTNO(u"§ 106.2") ctx.SUBJECT(" Definitions ") ctx.P(" Except as otherwise provided, the following apply. ") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['106']} build.process_amendments(notice, ctx.xml) self.assertEqual('[text]', notice['changes']['106-2'][0]['field'])
def test_introductory_text(self): """ Sometimes notices change just the introductory text of a paragraph (instead of changing the entire paragraph tree). """ with self.tree.builder("REGTEXT", PART="106", TITLE="12") as regtext: regtext.AMDPAR(u"3. In § 106.2, revise the introductory text to " "read as follows:") with regtext.SECTION() as section: section.SECTNO(u"§ 106.2") section.SUBJECT(" Definitions ") section.P(" Except as otherwise provided, the following " "apply. ") notice = {'cfr_parts': ['106']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual('[text]', notice['changes']['106-2'][0]['field'])
def test_process_amendments_markerless(self): with self.tree.builder("REGTEXT", PART="105", TITLE="12") as regtext: regtext.AMDPAR(u"1. Revise [label:105-11-p5] as blah") with regtext.SECTION() as section: section.SECTNO(u"§ 105.11") section.SUBJECT("Purpose.") section.STARS() section.P("Some text here") notice = {'cfr_parts': ['105']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual(notice['changes'].keys(), ['105-11-p5']) changes = notice['changes']['105-11-p5'][0] self.assertEqual(changes['action'], 'PUT')
def test_process_amendments_markerless(self): with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx: ctx.AMDPAR(u"1. Revise [label:105-11-p5] as blah") with ctx.SECTION(): ctx.SECTNO(u"§ 105.11") ctx.SUBJECT("Purpose.") ctx.STARS() ctx.P("Some text here") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, ctx.xml) self.assertItemsEqual(notice['changes'].keys(), ['105-11-p5']) changes = notice['changes']['105-11-p5'][0] self.assertEqual(changes['action'], 'PUT')
def test_process_amendments_context(self): """Context should carry over between REGTEXTs""" with self.tree.builder("ROOT") as root: with root.REGTEXT(TITLE="12") as regtext: regtext.AMDPAR(u"3. In § 106.1, revise paragraph (a) to " "read as follows:") with root.REGTEXT(TITLE="12") as regtext: regtext.AMDPAR("3. Add appendix C") notice = {'cfr_parts': ['105', '106']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual(2, len(notice['amendments'])) amd1, amd2 = notice['amendments'] self.assertEqual(['106', '1', 'a'], amd1.label) self.assertEqual(['106', 'C'], amd2.label)
def test_process_amendments(self): with self.tree.builder("REGTEXT", PART="105", TITLE="12") as regtext: with regtext.SUBPART() as subpart: subpart.HD(u"Subpart A—General", SOURCE="HED") regtext.AMDPAR(u"2. Designate §§ 105.1 through 105.3 as subpart " "A under the heading.") notice = {'cfr_parts': ['105']} build.process_amendments(notice, self.tree.render_xml()) section_list = ['105-2', '105-3', '105-1'] self.assertEqual(notice['changes'].keys(), section_list) for l, c in notice['changes'].items(): change = c[0] self.assertEqual(change['destination'], ['105', 'Subpart', 'A']) self.assertEqual(change['action'], 'DESIGNATE')
def test_process_amendments_context(self): """Context should carry over between REGTEXTs""" with XMLBuilder("ROOT") as ctx: with ctx.REGTEXT(TITLE="12"): ctx.AMDPAR(u"3. In § 106.1, revise paragraph (a) to read as " u"follows:") with ctx.REGTEXT(TITLE="12"): ctx.AMDPAR("3. Add appendix C") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['105', '106']} build.process_amendments(notice, ctx.xml) self.assertEqual(2, len(notice['amendments'])) amd1, amd2 = notice['amendments'] self.assertEqual(['106', '1', 'a'], amd1.label) self.assertEqual(['106', 'C'], amd2.label)
def test_process_amendments_insert_in_order(self): with self.tree.builder("ROOT") as root: with root.REGTEXT(TITLE="10") as regtext: regtext.AMDPAR('[insert-in-order] [label:123-45-p6]') with regtext.SECTION() as section: section.SECTNO(u"§ 123.45") section.SUBJECT("Some Subject.") section.STARS() section.P("This is the sixth paragraph") section.STARS() notice = {'cfr_parts': ['123']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual(1, len(notice['amendments'])) amendment = notice['amendments'][0] self.assertEqual(['123', '45', 'p6'], amendment.label) self.assertEqual('INSERT', amendment.action)
def test_process_amendments_insert_in_order(self): with XMLBuilder("ROOT") as ctx: with ctx.REGTEXT(TITLE="10"): ctx.AMDPAR('[insert-in-order] [label:123-45-p6]') with ctx.SECTION(): ctx.SECTNO(u"§ 123.45") ctx.SUBJECT("Some Subject.") ctx.STARS() ctx.P("This is the sixth paragraph") ctx.STARS() ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['123']} build.process_amendments(notice, ctx.xml) self.assertEqual(1, len(notice['amendments'])) amendment = notice['amendments'][0] self.assertEqual(['123', '45', 'p6'], amendment.label) self.assertEqual('INSERT', amendment.action)
def test_process_amendments_no_nodes(self): xml = u""" <ROOT> <REGTEXT PART="104" TITLE="12"> <AMDPAR> 1. In § 104.13, paragraph (b) is removed </AMDPAR> </REGTEXT> </ROOT>""" notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['104']} build.process_amendments(notice, notice_xml) self.assertEqual(1, len(notice['amendments'])) delete = notice['amendments'][0] self.assertEqual(delete.action, 'DELETE') self.assertEqual(delete.label, ['104', '13', 'b'])
def test_process_amendments_no_nodes(self): xml = u""" <ROOT> <REGTEXT PART="104" TITLE="12"> <AMDPAR> 1. In § 104.13, paragraph (b) is removed </AMDPAR> </REGTEXT> </ROOT>""" notice_xml = etree.fromstring(xml) notice = {"cfr_parts": ["104"]} build.process_amendments(notice, notice_xml) self.assertEqual(1, len(notice["amendments"])) delete = notice["amendments"][0] self.assertEqual(delete.action, "DELETE") self.assertEqual(delete.label, ["104", "13", "b"])
def test_process_amendments(self): with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx: with ctx.SUBPART(): ctx.HD(u"Subpart A—General", SOURCE="HED") ctx.AMDPAR(u"2. Designate §§ 105.1 through 105.3 as subpart A " u"under the heading.") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, ctx.xml) section_list = ['105-2', '105-3', '105-1'] self.assertItemsEqual(notice['changes'].keys(), section_list) for l, c in notice['changes'].items(): change = c[0] self.assertEqual(change['destination'], ['105', 'Subpart', 'A']) self.assertEqual(change['action'], 'DESIGNATE')
def test_multiple_changes(self): """ A notice can have two modifications to a paragraph. """ with self.tree.builder("ROOT") as root: with root.REGTEXT(PART="106", TITLE="12") as regtext: regtext.AMDPAR(u"2. Designate §§ 106.1 through 106.3 as " "subpart A under the heading.") with root.REGTEXT(PART="106", TITLE="12") as regtext: regtext.AMDPAR(u"3. In § 106.2, revise the introductory text " "to read as follows:") with regtext.SECTION() as section: section.SECTNO(u"§ 106.2") section.SUBJECT(" Definitions ") section.P(" Except as otherwise provided, the following " "apply. ") notice = {'cfr_parts': ['106']} build.process_amendments(notice, self.tree.render_xml()) self.assertEqual(2, len(notice['changes']['106-2']))
def test_multiple_changes(self): """ A notice can have two modifications to a paragraph. """ with XMLBuilder("ROOT") as ctx: with ctx.REGTEXT(PART="106", TITLE="12"): ctx.AMDPAR(u"2. Designate §§ 106.1 through 106.3 as subpart " u"A under the heading.") with ctx.REGTEXT(PART="106", TITLE="12"): ctx.AMDPAR(u"3. In § 106.2, revise the introductory text to " u"read as follows:") with ctx.SECTION(): ctx.SECTNO(u"§ 106.2") ctx.SUBJECT(" Definitions ") ctx.P(" Except as otherwise provided, the following " "apply. ") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['106']} build.process_amendments(notice, ctx.xml) self.assertEqual(2, len(notice['changes']['106-2']))
def test_process_amendments_multiple_sections(self): """Regression test verifying multiple SECTIONs in the same REGTEXT""" with XMLBuilder("REGTEXT", PART="111") as ctx: ctx.AMDPAR(u"1. Modify § 111.22 by revising paragraph (b)") with ctx.SECTION(): ctx.SECTNO(u"§ 111.22") ctx.SUBJECT("Subject Here.") ctx.STARS() ctx.P("(b) Revised second paragraph") ctx.AMDPAR(u"2. Modify § 111.33 by revising paragraph (c)") with ctx.SECTION(): ctx.SECTNO(u"§ 111.33") ctx.SUBJECT("Another Subject") ctx.STARS() ctx.P("(c) Revised third paragraph") ParseAMDPARs().transform(ctx.xml) notice = {'cfr_parts': ['111']} build.process_amendments(notice, ctx.xml) self.assertItemsEqual(notice['changes'].keys(), ['111-22-b', '111-33-c'])
def test_process_amendments(self): xml = u""" <REGTEXT PART="105" TITLE="12"> <SUBPART> <HD SOURCE="HED">Subpart A—General</HD> </SUBPART> <AMDPAR> 2. Designate §§ 105.1 through 105.3 as subpart A under the heading. </AMDPAR> </REGTEXT>""" notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['105']} build.process_amendments(notice, notice_xml) section_list = ['105-2', '105-3', '105-1'] self.assertEqual(notice['changes'].keys(), section_list) for l, c in notice['changes'].items(): change = c[0] self.assertEqual(change['destination'], ['105', 'Subpart', 'A']) self.assertEqual(change['action'], 'DESIGNATE')
def test_introductory_text(self): """ Sometimes notices change just the introductory text of a paragraph (instead of changing the entire paragraph tree). """ xml = u""" <REGTEXT PART="106" TITLE="12"> <AMDPAR> 3. In § 106.2, revise the introductory text to read as follows: </AMDPAR> <SECTION> <SECTNO>§ 106.2</SECTNO> <SUBJECT> Definitions </SUBJECT> <P> Except as otherwise provided, the following apply. </P> </SECTION> </REGTEXT> """ notice_xml = etree.fromstring(xml) notice = {'cfr_parts': ['106']} build.process_amendments(notice, notice_xml) self.assertEqual('[text]', notice['changes']['106-2'][0]['field'])
def parse_rule_changes(document_number): """Parse changes present in a single rule. DOCUMENT_NUMBER is the identifier associated with a final rule. If a rule has been split, use the split identifiers, a.k.a. version ids.""" rule_entry = entry.RuleChanges(document_number) notice_entry = entry.Notice(document_number) deps = dependency.Graph() deps.add(rule_entry, notice_entry) deps.validate_for(rule_entry) # We don't check for staleness as we want to always execute when given a # specific file to process notice_xml = notice_entry.read() notice = process_amendments({'cfr_parts': notice_xml.cfr_parts}, notice_xml.xml) rule_entry.write(notice)