def test_process_amendments_context(monkeypatch):
    """Context should carry over between REGTEXTs"""
    # turn on the interpretations plugin
    monkeypatch.setattr(
        fetch, 'instantiate_if_possible',
        Mock(return_value=[
            appendix.content_for_appendix, section.content_for_regtext
        ]))
    amdpar1 = "3. In § 106.1, revise paragraph (a) to read as follows:"
    amdpar2 = "3. Add appendix C"
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(TITLE="12"):
            ctx.AMDPAR(amdpar1)
            with ctx.SECTION():
                ctx.SECTNO("§ 106.1")
                ctx.SUBJECT("Some Subject.")
                ctx.P("(a) Something new")
        with ctx.REGTEXT(TITLE="12"):
            ctx.AMDPAR(amdpar2)
            ctx.HD("Appendix C to Part 106", SOURCE="HD1")
            with ctx.EXTRACT():
                ctx.P("Text")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '106'
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '106'
    assert ['106-1-a'] == [c[0] for c in amd1['changes']]
    assert ['106-C', '106-C-p1'] == list(sorted(c[0] for c in amd2['changes']))
Example #2
0
def test_multiple_changes(monkeypatch):
    """ A notice can have two modifications to a paragraph. """
    amdpar1 = ("2. Designate §§ 106.1 through 106.3 as subpart A under "
               "the heading.")
    amdpar2 = "3. In § 106.2, revise the introductory text to read:"
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART="106", TITLE="12"):
            ctx.AMDPAR(amdpar1)
        with ctx.REGTEXT(PART="106", TITLE="12"):
            ctx.AMDPAR(amdpar2)
            with ctx.SECTION():
                ctx.SECTNO("§ 106.2")
                ctx.SUBJECT(" Definitions ")
                ctx.P(" Except as otherwise provided, the following "
                      "apply. ")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    changes1, changes2 = dict(amd1['changes']), dict(amd2['changes'])
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '106'
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '106'
    assert len(changes1['106-2']) == 1
    assert len(changes2['106-2']) == 1
Example #3
0
def test_process_amendments_restart_new_section(monkeypatch):
    # turn on the interpretations plugin
    monkeypatch.setattr(fetch, 'instantiate_if_possible', Mock(return_value=[
        amendments.content_for_interpretations, section.content_for_regtext
    ]))

    amdpar1 = "1. In Supplement I to Part 104, comment 22(a) is added"
    amdpar2 = "3. In § 105.1, revise paragraph (b) to read as follows:"
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART="104", TITLE="12"):
            ctx.AMDPAR(amdpar1)
            ctx.HD("SUPPLEMENT I", SOURCE='HED')
            ctx.HD("22(a)", SOURCE='HD1')
            ctx.P("1. Content")
        with ctx.REGTEXT(PART="105", TITLE="12"):
            ctx.AMDPAR(amdpar2)
            with ctx.SECTION():
                ctx.SECTNO("§ 105.1")
                ctx.SUBJECT("Purpose.")
                ctx.STARS()
                ctx.P("(b) This part carries out.")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    changes1, changes2 = dict(amd1['changes']), dict(amd2['changes'])
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '104'
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '105'
    assert '104-22-a-Interp' in changes1
    assert '105-1-b' in changes2

    assert changes1['104-22-a-Interp'][0]['action'] == 'POST'
    assert changes2['105-1-b'][0]['action'] == 'PUT'
def test_process_amendments_multiple_sections():
    """Regression test verifying multiple SECTIONs in the same REGTEXT"""
    amdpar1 = "1. Modify § 111.22 by revising paragraph (b)"
    amdpar2 = "2. Modify § 111.33 by revising paragraph (c)"
    with XMLBuilder("REGTEXT", PART="111") as ctx:
        ctx.AMDPAR(amdpar1)
        with ctx.SECTION():
            ctx.SECTNO("§ 111.22")
            ctx.SUBJECT("Subject Here.")
            ctx.STARS()
            ctx.P("(b) Revised second paragraph")
        ctx.AMDPAR(amdpar2)
        with ctx.SECTION():
            ctx.SECTNO("§ 111.33")
            ctx.SUBJECT("Another Subject")
            ctx.STARS()
            ctx.P("(c) Revised third paragraph")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '111'
    assert ['111-22-b'] == [c[0] for c in amd1['changes']]
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '111'
    assert ['111-33-c'] == [c[0] for c in amd2['changes']]
Example #5
0
def test_process_amendments_subpart(monkeypatch):
    with XMLBuilder("RULE") as ctx:
        with ctx.REGTEXT(PART="105", TITLE="12"):
            ctx.AMDPAR("3. In § 105.1, revise paragraph (b) to read as"
                       "follows:")
            with ctx.SECTION():
                ctx.SECTNO("§ 105.1")
                ctx.SUBJECT("Purpose.")
                ctx.STARS()
                ctx.P("(b) This part carries out.")
        with ctx.REGTEXT(PART="105", TITLE="12"):
            ctx.AMDPAR("6. Add subpart B to read as follows:")
            with ctx.CONTENTS():
                with ctx.SUBPART():
                    ctx.SECHD("Sec.")
                    ctx.SECTNO("105.30")
                    ctx.SUBJECT("First In New Subpart.")
            with ctx.SUBPART():
                ctx.HD("Subpart B—Requirements", SOURCE="HED")
                with ctx.SECTION():
                    ctx.SECTNO("105.30")
                    ctx.SUBJECT("First In New Subpart")
                    ctx.P("For purposes of this subpart, the follow " "apply:")
                    ctx.P('(a) "Agent" means agent.')

    preprocess_amdpars(ctx.xml)

    subpart_amendment = fetch.fetch_amendments(ctx.xml)[1]
    changes = dict(subpart_amendment['changes'])

    assert '105-Subpart-B' in changes
    assert '105-30-a' in changes
    assert '105-30' in changes
def test_process_amendments_multiple_in_same_parent():
    amdpar1 = "1. In § 105.1, revise paragraph (b) to read as follows:"
    amdpar2 = "2. Also, revise paragraph (c):"
    with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx:
        ctx.AMDPAR(amdpar1)
        ctx.AMDPAR(amdpar2)
        with ctx.SECTION():
            ctx.SECTNO("§ 105.1")
            ctx.SUBJECT("Purpose.")
            ctx.STARS()
            ctx.P("(b) This part carries out.")
            ctx.P("(c) More stuff")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    changes1, changes2 = dict(amd1['changes']), dict(amd2['changes'])
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '105'
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '105'
    assert ['105-1-b'] == list(changes1.keys())
    assert ['105-1-c'] == list(changes2.keys())

    changes = changes1['105-1-b'][0]
    assert changes['action'] == 'PUT'
    assert changes['node']['text'] == '(b) This part carries out.'
    changes = changes2['105-1-c'][0]
    assert changes['action'] == 'PUT'
    assert changes['node']['text'] == '(c) More stuff'
def test_process_amendments_multiple_in_same_parent():
    amdpar1 = "1. In § 105.1, revise paragraph (b) to read as follows:"
    amdpar2 = "2. Also, revise paragraph (c):"
    with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx:
        ctx.AMDPAR(amdpar1)
        ctx.AMDPAR(amdpar2)
        with ctx.SECTION():
            ctx.SECTNO("§ 105.1")
            ctx.SUBJECT("Purpose.")
            ctx.STARS()
            ctx.P("(b) This part carries out.")
            ctx.P("(c) More stuff")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    changes1, changes2 = dict(amd1['changes']), dict(amd2['changes'])
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '105'
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '105'
    assert ['105-1-b'] == list(changes1.keys())
    assert ['105-1-c'] == list(changes2.keys())

    changes = changes1['105-1-b'][0]
    assert changes['action'] == 'PUT'
    assert changes['node']['text'] == '(b) This part carries out.'
    changes = changes2['105-1-c'][0]
    assert changes['action'] == 'PUT'
    assert changes['node']['text'] == '(c) More stuff'
def test_process_amendments_multiple_sections():
    """Regression test verifying multiple SECTIONs in the same REGTEXT"""
    amdpar1 = "1. Modify § 111.22 by revising paragraph (b)"
    amdpar2 = "2. Modify § 111.33 by revising paragraph (c)"
    with XMLBuilder("REGTEXT", PART="111") as ctx:
        ctx.AMDPAR(amdpar1)
        with ctx.SECTION():
            ctx.SECTNO("§ 111.22")
            ctx.SUBJECT("Subject Here.")
            ctx.STARS()
            ctx.P("(b) Revised second paragraph")
        ctx.AMDPAR(amdpar2)
        with ctx.SECTION():
            ctx.SECTNO("§ 111.33")
            ctx.SUBJECT("Another Subject")
            ctx.STARS()
            ctx.P("(c) Revised third paragraph")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '111'
    assert ['111-22-b'] == [c[0] for c in amd1['changes']]
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '111'
    assert ['111-33-c'] == [c[0] for c in amd2['changes']]
def test_process_amendments_mix_regs():
    """Some notices apply to multiple regs. For now, just ignore the
    sections not associated with the reg we're focused on"""
    amdpar1 = "3. In § 105.1, revise paragraph (a) to read as follows:"
    amdpar2 = "3. In § 106.3, revise paragraph (b) to read as follows:"
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART="105", TITLE="12"):
            ctx.AMDPAR(amdpar1)
            with ctx.SECTION():
                ctx.SECTNO("§ 105.1")
                ctx.SUBJECT("105Purpose.")
                ctx.P("(a) 105Content")
        with ctx.REGTEXT(PART="106", TITLE="12"):
            ctx.AMDPAR(amdpar2)
            with ctx.SECTION():
                ctx.SECTNO("§ 106.3")
                ctx.SUBJECT("106Purpose.")
                ctx.P("(b) Content")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '105'
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '106'
    assert ['105-1-a'] == [c[0] for c in amd1['changes']]
    assert ['106-3-b'] == [c[0] for c in amd2['changes']]
Example #10
0
def test_process_amendments_mix_regs():
    """Some notices apply to multiple regs. For now, just ignore the
    sections not associated with the reg we're focused on"""
    amdpar1 = "3. In § 105.1, revise paragraph (a) to read as follows:"
    amdpar2 = "3. In § 106.3, revise paragraph (b) to read as follows:"
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART="105", TITLE="12"):
            ctx.AMDPAR(amdpar1)
            with ctx.SECTION():
                ctx.SECTNO("§ 105.1")
                ctx.SUBJECT("105Purpose.")
                ctx.P("(a) 105Content")
        with ctx.REGTEXT(PART="106", TITLE="12"):
            ctx.AMDPAR(amdpar2)
            with ctx.SECTION():
                ctx.SECTNO("§ 106.3")
                ctx.SUBJECT("106Purpose.")
                ctx.P("(b) Content")
    preprocess_amdpars(ctx.xml)

    amd1, amd2 = fetch.fetch_amendments(ctx.xml)
    assert amd1['instruction'] == amdpar1
    assert amd1['cfr_part'] == '105'
    assert amd2['instruction'] == amdpar2
    assert amd2['cfr_part'] == '106'
    assert ['105-1-a'] == [c[0] for c in amd1['changes']]
    assert ['106-3-b'] == [c[0] for c in amd2['changes']]
def test_preprocess_amdpars_final_context():
    """The "final_context" attribute should be written"""
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART=111):
            ctx.AMDPAR("Remove section 2(b), revise section 3(c), add "
                       "section 4(d)(3)")
    preprocessors.preprocess_amdpars(ctx.xml)
    instructions = ctx.xml.xpath('//AMDPAR/EREGS_INSTRUCTIONS')
    assert len(instructions) == 1
    assert instructions[0].get('final_context') == '111-?-4-d-3'
def test_preprocess_amdpars_dont_touch_manual():
    """Should not modify existing instructions"""
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART=111):
            with ctx.AMDPAR("Revise section 22(c)"):
                with ctx.EREGS_INSTRUCTIONS():
                    # Completely unrelated to the AMDPAR
                    ctx.DELETE(label='222-?-5')
    original = ctx.xml_str
    preprocessors.preprocess_amdpars(ctx.xml)
    assert original == ctx.xml_str
def test_process_amendments_no_nodes():
    amdpar = "1. In § 104.13, paragraph (b) is removed"
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART="104", TITLE="12"):
            ctx.AMDPAR(amdpar)
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '104'
    assert '104-13-b' in changes
    assert changes['104-13-b'][0]['action'] == 'DELETE'
def test_introductory_text():
    """ 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("3. In § 106.2, revise the introductory text to read:")
        with ctx.SECTION():
            ctx.SECTNO("§ 106.2")
            ctx.SUBJECT(" Definitions ")
            ctx.P(" Except as otherwise provided, the following apply. ")
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    change = dict(amendment['changes'])['106-2'][0]
    assert change.get('field') == '[text]'
Example #15
0
def test_introductory_text():
    """ 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("3. In § 106.2, revise the introductory text to read:")
        with ctx.SECTION():
            ctx.SECTNO("§ 106.2")
            ctx.SUBJECT(" Definitions ")
            ctx.P(" Except as otherwise provided, the following apply. ")
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    change = dict(amendment['changes'])['106-2'][0]
    assert change.get('field') == '[text]'
Example #16
0
def test_process_amendments_no_nodes():
    amdpar = "1. In § 104.13, paragraph (b) is removed"
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(PART="104", TITLE="12"):
            ctx.AMDPAR(amdpar)
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '104'
    assert '104-13-b' in changes
    assert changes['104-13-b'][0]['action'] == 'DELETE'
def test_preprocess_amdpars_derives_part():
    """Associates the closest PART info when parsing AMDPARs"""
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT():
            ctx.AMDPAR("Revise section 14(a)")
        with ctx.REGTEXT(PART=1111):
            ctx.AMDPAR("Revise section 15(b)")
        with ctx.REGTEXT(PART=2222):
            ctx.AMDPAR("Revise section 16(c)")
        with ctx.REGTEXT():
            ctx.AMDPAR("Revise section 17(d)")
    preprocessors.preprocess_amdpars(ctx.xml)
    puts = ctx.xml.xpath('//AMDPAR/EREGS_INSTRUCTIONS/PUT')
    labels = [put.get('label') for put in puts]
    assert labels == ['1111-?-14-a', '1111-?-15-b', '2222-?-16-c',
                      '2222-?-17-d']
Example #18
0
def test_process_amendments_authority():
    amdpar = ('1. The authority citation for 27 CFR Part 555 continues to '
              'read as follows:')
    auth = '18 U.S.C. 847.'
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(TITLE="27", PART="555"):
            ctx.AMDPAR(amdpar)
            with ctx.AUTH():
                ctx.HD("Authority:", SOURCE="HED")
                ctx.P(auth)
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '555'
    assert amendment['authority'] == auth
    assert 'changes' not in amendment
def test_process_amendments_markerless():
    amdpar = "1. Revise [label:105-11-p5] as blah"
    with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx:
        ctx.AMDPAR(amdpar)
        with ctx.SECTION():
            ctx.SECTNO("§ 105.11")
            ctx.SUBJECT("Purpose.")
            ctx.STARS()
            ctx.P("Some text here")
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '105'
    assert ['105-11-p5'] == list(changes.keys())
    changes = changes['105-11-p5'][0]
    assert changes['action'] == 'PUT'
Example #20
0
def test_process_amendments_markerless():
    amdpar = "1. Revise [label:105-11-p5] as blah"
    with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx:
        ctx.AMDPAR(amdpar)
        with ctx.SECTION():
            ctx.SECTNO("§ 105.11")
            ctx.SUBJECT("Purpose.")
            ctx.STARS()
            ctx.P("Some text here")
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '105'
    assert ['105-11-p5'] == list(changes.keys())
    changes = changes['105-11-p5'][0]
    assert changes['action'] == 'PUT'
def test_process_amendments_insert_in_order():
    amdpar = '[insert-in-order] [label:123-45-p6]'
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(TITLE="10"):
            ctx.AMDPAR(amdpar)
            with ctx.SECTION():
                ctx.SECTNO("§ 123.45")
                ctx.SUBJECT("Some Subject.")
                ctx.STARS()
                ctx.P("This is the sixth paragraph")
                ctx.STARS()
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '123'
    assert ['123-45-p6'] == list(changes.keys())
    assert changes['123-45-p6'][0]['action'] == 'INSERT'
Example #22
0
def test_process_amendments_insert_in_order():
    amdpar = '[insert-in-order] [label:123-45-p6]'
    with XMLBuilder("ROOT") as ctx:
        with ctx.REGTEXT(TITLE="10"):
            ctx.AMDPAR(amdpar)
            with ctx.SECTION():
                ctx.SECTNO("§ 123.45")
                ctx.SUBJECT("Some Subject.")
                ctx.STARS()
                ctx.P("This is the sixth paragraph")
                ctx.STARS()
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '123'
    assert ['123-45-p6'] == list(changes.keys())
    assert changes['123-45-p6'][0]['action'] == 'INSERT'
Example #23
0
def test_process_amendments():
    amdpar = ("2. Designate §§ 105.1 through 105.3 as subpart A under the "
              "heading.")
    with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx:
        with ctx.SUBPART():
            ctx.HD("Subpart A—General", SOURCE="HED")
        ctx.AMDPAR(amdpar)
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '105'
    assert ['105-1', '105-2', '105-3'] == list(sorted(changes.keys()))
    for change_list in changes.values():
        assert len(change_list) == 1
        change = change_list[0]
        assert change['destination'] == ['105', 'Subpart', 'A']
        assert change['action'] == 'DESIGNATE'
def test_process_amendments_section():
    amdpar = "3. In § 105.1, revise paragraph (b) to read as follows:"
    with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx:
        ctx.AMDPAR(amdpar)
        with ctx.SECTION():
            ctx.SECTNO("§ 105.1")
            ctx.SUBJECT("Purpose.")
            ctx.STARS()
            ctx.P("(b) This part carries out.")
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '105'
    assert ['105-1-b'] == list(changes.keys())

    changes = changes['105-1-b'][0]
    assert changes['action'] == 'PUT'
    assert changes['node']['text'] == '(b) This part carries out.'
Example #25
0
def test_process_amendments_section():
    amdpar = "3. In § 105.1, revise paragraph (b) to read as follows:"
    with XMLBuilder("REGTEXT", PART="105", TITLE="12") as ctx:
        ctx.AMDPAR(amdpar)
        with ctx.SECTION():
            ctx.SECTNO("§ 105.1")
            ctx.SUBJECT("Purpose.")
            ctx.STARS()
            ctx.P("(b) This part carries out.")
    preprocess_amdpars(ctx.xml)

    amendment = fetch.fetch_amendments(ctx.xml)[0]
    changes = dict(amendment['changes'])

    assert amendment['instruction'] == amdpar
    assert amendment['cfr_part'] == '105'
    assert ['105-1-b'] == list(changes.keys())

    changes = changes['105-1-b'][0]
    assert changes['action'] == 'PUT'
    assert changes['node']['text'] == '(b) This part carries out.'