コード例 #1
0
def test_dependencies():
    """Expect nonexistent trees to depend on their predecessor, associated
    rule changes and version files. Shouldn't add dependencies for the
    first version, if missing"""
    versions = [Version(str(i)*3, date(2001, i, i), date(2002, i, i))
                for i in range(1, 7)]
    parents = Version.parents_of(versions)
    tree_dir = entry.Tree('12', '1000')
    notice_dir = entry.Notice()
    vers_dir = entry.Version('12', '1000')
    # Existing trees
    (tree_dir / '222').write(Node())
    (tree_dir / '555').write(Node())

    deps = fill_with_rules.dependencies(tree_dir, vers_dir,
                                        list(zip(versions, parents)))

    # First is skipped, as we can't build it from a rule
    assert str(tree_dir / '111') not in deps
    # Second can also be skipped as a tree already exists
    assert deps.dependencies(str(tree_dir / '222')) == []
    # Third relies on the associated versions and the second tree
    expected = {str(tree_dir / '222'), str(notice_dir / '333'),
                str(vers_dir / '333')}
    assert set(deps.dependencies(str(tree_dir / '333'))) == expected
    # Fourth relies on the third, even though it's not been built
    expected = {str(tree_dir / '333'), str(notice_dir / '444'),
                str(vers_dir / '444')}
    assert set(deps.dependencies(str(tree_dir / '444'))) == expected
    # Fifth can be skipped as the tree already exists
    assert deps.dependencies(str(tree_dir / '555')) == []
    # Six relies on the fifth
    expected = {str(tree_dir / '555'), str(notice_dir / '666'),
                str(vers_dir / '666')}
    assert set(deps.dependencies(str(tree_dir / '666'))) == expected
コード例 #2
0
 def create_versions(self):
     entry.Version(11, 222, 'aaa').write(
         Version('aaa', date(2002, 2, 2), date(2002, 2, 2)))
     entry.Version(11, 222, 'bbb').write(
         Version('bbb', date(2001, 1, 1), date(2001, 1, 1)))
     entry.Version(11, 222, 'ccc').write(
         Version('ccc', date(2003, 3, 3), date(2003, 3, 3)))
コード例 #3
0
def test_order():
    v1 = Version('first', date(2001, 1, 1), Citation(1, 1))
    v2 = Version('eff', date(2002, 2, 2), Citation(1, 1))
    v3 = Version('cit', date(2002, 2, 2), Citation(3, 3))
    v4 = Version('cit >id', date(2002, 2, 2), Citation(3, 3))

    for permutation in permutations([v1, v2, v3, v4]):
        assert list(sorted(permutation)) == [v1, v2, v3, v4]
コード例 #4
0
    def test_order(self):
        v1 = Version('first', date(2001, 1, 1), date(2001, 1, 1))
        v2 = Version('eff', date(2001, 1, 1), date(2002, 2, 2))
        v3 = Version('pub', date(2003, 3, 3), date(2002, 2, 2))
        v4 = Version('pub >id', date(2003, 3, 3), date(2002, 2, 2))

        for permutation in permutations([v1, v2, v3, v4]):
            self.assertEqual(sorted(permutation), [v1, v2, v3, v4])
コード例 #5
0
def create_versions():
    """Generate some dummy data"""
    entry.Version(11, 222,
                  'aaa').write(Version('aaa', date(2002, 2, 2), Citation(2,
                                                                         2)))
    entry.Version(11, 222,
                  'bbb').write(Version('bbb', date(2001, 1, 1), Citation(1,
                                                                         1)))
    entry.Version(11, 222,
                  'ccc').write(Version('ccc', date(2003, 3, 3), Citation(3,
                                                                         3)))
コード例 #6
0
def test_last_versions_not_printed(monkeypatch):
    """We should only find the annual editions which have been published
    already"""
    # 2001 exists; no other years do
    monkeypatch.setattr(annual_editions.annual, 'find_volume', Mock())
    annual_editions.annual.find_volume = lambda year, title, part: year == 2001
    path = entry.Version('12', '1000')
    (path / '1111').write(Version('1111', date(2000, 12, 1), Citation(1, 1)))
    (path / '2222').write(Version('2222', date(2001, 12, 1), Citation(1, 1)))

    results = list(annual_editions.last_versions(12, 1000))
    assert results == [annual_editions.LastVersionInYear('1111', 2001)]
コード例 #7
0
    def test_last_versions_not_printed(self, find_volume):
        """We should only find the annual editions which have been published
        already"""
        # 2001 exists; no other years do
        find_volume.side_effect = lambda year, title, part: year == 2001
        with self.cli.isolated_filesystem():
            path = entry.Version('12', '1000')
            (path / '1111').write(
                Version('1111', date(2000, 12, 1), date(2000, 12, 1)))
            (path / '2222').write(
                Version('2222', date(2001, 12, 1), date(2001, 12, 1)))

            results = list(annual_editions.last_versions(12, 1000))
            self.assertEqual(results,
                             [annual_editions.LastVersionInYear('1111', 2001)])
コード例 #8
0
def test_last_versions_multiple_versions(monkeypatch):
    """If multiple versions affect the same annual edition, we should only
    receive the last"""
    monkeypatch.setattr(annual_editions.annual, 'find_volume', Mock())
    annual_editions.annual.find_volume.return_value = True
    path = entry.Version('12', '1000')
    (path / '1111').write(Version('1111', date(2000, 12, 1), Citation(1, 1)))
    (path / '2222').write(Version('2222', date(2000, 12, 2), Citation(1, 2)))
    (path / '3333').write(Version('3333', date(2001, 12, 1), Citation(1, 1)))

    results = list(annual_editions.last_versions(12, 1000))
    assert results == [
        annual_editions.LastVersionInYear('2222', 2001),
        annual_editions.LastVersionInYear('3333', 2002)
    ]
コード例 #9
0
    def test_process_if_needed_missing_writes(self, xml_parser):
        """If output isn't already present, we should process. If it is
        present, we don't need to, unless a dependency has changed."""
        with self.cli.isolated_filesystem():
            build_tree = xml_parser.reg_text.build_tree
            build_tree.return_value = Node()
            last_versions = [annual_editions.LastVersionInYear('1111', 2000)]
            entry.Version('12', '1000', '1111').write(
                Version('1111', date(2000, 1, 1), date(2000, 1, 1)))
            entry.Entry('annual', '12', '1000', 2000).write(
                b'<ROOT></ROOT>')

            annual_editions.process_if_needed('12', '1000', last_versions)
            self.assertTrue(build_tree.called)

            build_tree.reset_mock()
            entry.Entry('tree', '12', '1000', '1111').write(b'tree-here')
            annual_editions.process_if_needed('12', '1000', last_versions)
            self.assertFalse(build_tree.called)

            # Simulate a change to an input file
            label_id = str(entry.Annual(12, 1000, 2000))
            new_time = timezone.now() + timedelta(hours=1)
            DBEntry.objects.filter(label_id=label_id).update(modified=new_time)
            annual_editions.process_if_needed('12', '1000', last_versions)
            self.assertTrue(build_tree.called)
コード例 #10
0
    def test_stale_layers(self):
        """We should have dependencies between all of the layers and their
        associated trees. We should also tie the meta layer to the version"""
        configured_layers = {'cfr': {'keyterms': None, 'other': None}}
        with self.cli.isolated_filesystem(), patch.dict(
                layers.LAYER_CLASSES, configured_layers):
            version_entry = entry.Version(111, 22, 'aaa')
            version_entry.write(Version('aaa', date.today(), date.today()))
            tree_entry = entry.Tree(111, 22, 'aaa')
            # Use list() to instantiate
            self.assertRaises(dependency.Missing, list,
                              layers.stale_layers(tree_entry, 'cfr'))

            entry.Entry('tree', 111, 22, 'bbb').write(b'')  # wrong version
            self.assertRaises(dependency.Missing, list,
                              layers.stale_layers(tree_entry, 'cfr'))

            entry.Entry('tree', 111, 22, 'aaa').write(b'')
            six.assertCountEqual(self, layers.stale_layers(tree_entry, 'cfr'),
                                 ['keyterms', 'other'])

            self.assertIn(
                str(version_entry),
                dependency.Graph().dependencies(
                    str(entry.Layer.cfr(111, 22, 'aaa', 'meta'))))
コード例 #11
0
 def test_process_effective_date(self):
     """The effective date is derived from a Version object"""
     version = Version('v1', date(2004, 4, 4), date(2004, 4, 4))
     m = Meta(None, cfr_title=8, version=version)
     result = m.process(Node(label=['a']))
     self.assertEqual(1, len(result))
     self.assertEqual('2004-04-04', result[0].get('effective_date'))
コード例 #12
0
def test_process_if_needed_missing_writes(monkeypatch):
    """If output isn't already present, we should process. If it is present,
    we don't need to, unless a dependency has changed."""
    monkeypatch.setattr(annual_editions, 'gpo_cfr', Mock())
    build_tree = annual_editions.gpo_cfr.builder.build_tree
    build_tree.return_value = Node()
    last_versions = [annual_editions.LastVersionInYear('1111', 2000)]
    entry.Version('12', '1000', '1111').write(
        Version('1111', date(2000, 1, 1), Citation(1, 1)))
    entry.Entry('annual', '12', '1000', 2000).write(b'<ROOT></ROOT>')

    annual_editions.process_if_needed('12', '1000', last_versions)
    assert build_tree.called

    build_tree.reset_mock()
    entry.Entry('tree', '12', '1000', '1111').write(b'tree-here')
    annual_editions.process_if_needed('12', '1000', last_versions)
    assert not build_tree.called

    # Simulate a change to an input file
    label_id = str(entry.Annual(12, 1000, 2000))
    new_time = timezone.now() + timedelta(hours=1)
    DBEntry.objects.filter(label_id=label_id).update(modified=new_time)
    annual_editions.process_if_needed('12', '1000', last_versions)
    assert build_tree.called
コード例 #13
0
    def test_last_versions_multiple_versions(self, find_volume):
        """If multiple versions affect the same annual edition, we should only
        receive the last"""
        find_volume.return_value = True
        with self.cli.isolated_filesystem():
            path = entry.Version('12', '1000')
            (path / '1111').write(Version('1111', date(2000, 12, 1),
                                          date(2000, 12, 1)))
            (path / '2222').write(Version('2222', date(2000, 12, 2),
                                          date(2000, 12, 2)))
            (path / '3333').write(Version('3333', date(2001, 12, 1),
                                          date(2001, 12, 1)))

            results = list(annual_editions.last_versions(12, 1000))
            self.assertEqual(results, [
                annual_editions.LastVersionInYear('2222', 2001),
                annual_editions.LastVersionInYear('3333', 2002)])
コード例 #14
0
def write_to_disk(xml, version_entry, delay=None):
    """Serialize a Version instance to disk"""
    effective = xml.effective if delay is None else delay.until
    if not effective:
        raise InvalidEffectiveDate(xml.version_id)
    version = Version(identifier=xml.version_id, effective=effective,
                      published=xml.published)
    version_entry.write(version)
コード例 #15
0
    def test_transform_notice(self, process_sxs, add_footnotes):
        """We should add version information and the SxS functions should be
        called"""
        with CliRunner().isolated_filesystem():
            entry.Version(11, 222, 'v1').write(
                Version('v1', date(2001, 1, 1), date(2002, 2, 2)))
            entry.Version(11, 222, 'v2').write(
                Version('v2', date(2002, 2, 2), date(2003, 3, 3)))
            entry.Version(11, 222, 'v3').write(
                Version('v3', date(2003, 3, 3), date(2004, 4, 4)))
            entry.Version(11, 223, 'v1').write(
                Version('v1', date(2001, 1, 1), date(2002, 2, 2)))
            entry.Version(11, 224, 'v1').write(
                Version('v1', date(2001, 1, 1), date(2002, 2, 2)))
            entry.Version(11, 222, 'proposal').write(
                Version('proposal', date(2003, 6, 6), None))
            entry.Version(11, 223, 'proposal').write(
                Version('proposal', date(2003, 6, 6), None))

            notice_xml = Mock()
            notice_xml.as_dict.return_value = {}
            notice_xml.version_id = 'proposal'
            notice_xml.cfr_ref_pairs = [(11, 222), (11, 223)]

            result = transform_notice(notice_xml)
            self.assertEqual(result['versions'], {
                222: {'left': 'v3', 'right': 'proposal'},
                223: {'left': 'v1', 'right': 'proposal'}})

            self.assertTrue(process_sxs.called)
            self.assertTrue(add_footnotes.called)
コード例 #16
0
    def test_iterator(self):
        """Versions should be correctly linearized"""
        with CliRunner().isolated_filesystem():
            path = entry.Version("12", "1000")
            v1 = Version('1111',
                         effective=date(2004, 4, 4),
                         published=date(2004, 4, 4))
            v2 = Version('2222',
                         effective=date(2002, 2, 2),
                         published=date(2004, 4, 4))
            v3 = Version('3333',
                         effective=date(2004, 4, 4),
                         published=date(2003, 3, 3))
            (path / '1111').write(v1)
            (path / '2222').write(v2)
            (path / '3333').write(v3)

            self.assertEqual(['2222', '3333', '1111'], list(path))
コード例 #17
0
def test_drop_initial_orphan_versions():
    version_list = [Version(letter, None, None) for letter in 'abcdef']
    version_pairs = list(zip(version_list, [None] + version_list[1:]))
    existing = {'c', 'e'}

    result = fill_with_rules.drop_initial_orphans(version_pairs, existing)
    result = [pair[0].identifier for pair in result]

    assert result == ['c', 'd', 'e', 'f']
コード例 #18
0
def write_to_disk(xml, version_entry, delay=None):
    """Serialize a Version instance to disk"""
    effective = xml.effective if delay is None else delay.until
    if effective:
        version = Version(xml.version_id, effective, xml.fr_citation)
        version_entry.write(version)
    else:
        logger.warning("No effective date for this rule: %s. Skipping",
                       xml.version_id)
コード例 #19
0
def test_iterator():
    """Versions should be correctly linearized"""
    path = entry.Version("12", "1000")
    v1 = Version('1111',
                 effective=date(2004, 4, 4),
                 published=date(2004, 4, 4))
    v2 = Version('2222',
                 effective=date(2002, 2, 2),
                 published=date(2004, 4, 4))
    v3 = Version('3333',
                 effective=date(2004, 4, 4),
                 published=date(2003, 3, 3))
    (path / '1111').write(v1)
    (path / '2222').write(v2)
    (path / '3333').write(v3)

    actual = [child.path[-1] for child in path.sub_entries()]

    assert ['2222', '3333', '1111'] == actual
コード例 #20
0
def test_process_cfr_layers():
    """All layers for a single version should get written."""
    version_entry = entry.Version(12, 1000, '1234')
    version_entry.write(Version('1234', date.today(), Citation(1, 1)))
    entry.Tree('12', '1000', '1234').write(Node())

    layers.process_cfr_layers(['keyterms', 'meta'], 12, version_entry)

    assert entry.Layer.cfr(12, 1000, '1234', 'keyterms').exists()
    assert entry.Layer.cfr(12, 1000, '1234', 'meta').exists()
コード例 #21
0
def create_version_entry_if_needed(volume, cfr_part):
    """Only write the version entry if it doesn't already exist. If we
    overwrote one, we'd be invalidating all related trees, etc."""
    version_id = _version_id(volume.year, cfr_part)
    version_entries = entry.FinalVersion(volume.title, cfr_part)

    if version_id not in version_entries:
        (version_entries / version_id).write(
            Version(identifier=version_id,
                    effective=volume.publication_date,
                    published=volume.publication_date))
コード例 #22
0
def create_version_entry_if_needed(volume, cfr_part):
    """Only write the version entry if it doesn't already exist. If we
    overwrote one, we'd be invalidating all related trees, etc."""
    version_id = _version_id(volume.year, cfr_part)
    version_dir = entry.FinalVersion(volume.title, cfr_part)

    if version_id not in [c.path[-1] for c in version_dir.sub_entries()]:
        (version_dir / version_id).write(
            Version(version_id,
                    effective=volume.publication_date,
                    fr_citation=Citation(volume.vol_num, 1)))
コード例 #23
0
    def test_process_cfr_layers(self):
        """All layers for a single version should get written."""
        with self.cli.isolated_filesystem():
            version_entry = entry.Version(12, 1000, '1234')
            version_entry.write(Version('1234', date.today(), date.today()))
            entry.Tree('12', '1000', '1234').write(Node())

            layers.process_cfr_layers(['keyterms', 'meta'], 12, version_entry)

            self.assertTrue(
                entry.Layer.cfr(12, 1000, '1234', 'keyterms').exists())
            self.assertTrue(entry.Layer.cfr(12, 1000, '1234', 'meta').exists())
コード例 #24
0
def proposal_versions(doc_number):
    """Generate version entries associated with a proposal."""
    notice = entry.Notice(doc_number)
    if not notice.exists():
        raise dependency.Missing(str(notice), str(notice))

    notice = notice.read()
    version = Version(doc_number, notice.published, None)

    for cfr_title, cfr_part in notice.cfr_ref_pairs:
        version_entry = entry.Version(cfr_title, cfr_part, doc_number)
        if not version_entry.exists() or version_entry.read() != version:
            version_entry.write(version)
コード例 #25
0
def test_process_if_needed_missing_dependency_error():
    """If the annual XML or version isn't present, we should see a dependency
    error."""
    last_versions = [annual_editions.LastVersionInYear('1111', 2000)]

    with pytest.raises(dependency.Missing):
        annual_editions.process_if_needed('12', '1000', last_versions)

    entry.Version('12', '1000', '1111').write(
        Version('1111', date(2000, 1, 1), Citation(1, 1)))

    with pytest.raises(dependency.Missing):
        annual_editions.process_if_needed('12', '1000', last_versions)
 def test_creates_version(self, entry):
     notice = entry.Notice.return_value.read.return_value
     notice.published = date.today()
     notice.cfr_ref_pairs = [(11, 111), (11, 222), (22, 222), (22, 333)]
     with self.cli.isolated_filesystem():
         result = self.cli.invoke(proposal_versions, ['dddd'])
         self.assertIsNone(result.exception)
         self.assertEqual('dddd', entry.Notice.call_args[0][0])
         self.assertEqual([lst[0] for lst in entry.Version.call_args_list],
                          [(11, 111, 'dddd'), (11, 222, 'dddd'),
                           (22, 222, 'dddd'), (22, 333, 'dddd')])
         self.assertEqual(entry.Version.return_value.write.call_args[0][0],
                          Version('dddd', date.today(), None))
コード例 #27
0
    def test_process_if_needed_missing_dependency_error(self):
        """If the annual XML or version isn't present, we should see a
        dependency error."""
        with self.cli.isolated_filesystem():
            last_versions = [annual_editions.LastVersionInYear('1111', 2000)]

            with self.assertRaises(dependency.Missing):
                annual_editions.process_if_needed('12', '1000', last_versions)

            entry.Version('12', '1000', '1111').write(
                Version('1111', date(2000, 1, 1), date(2000, 1, 1)))

            with self.assertRaises(dependency.Missing):
                annual_editions.process_if_needed('12', '1000', last_versions)
コード例 #28
0
def process_version_if_needed(cfr_title, cfr_part, version_id):
    """Creates and writes a version struct after validating the Notice has
    been created"""
    notice_entry = entry.Notice(version_id)
    version_entry = entry.Version(cfr_title, cfr_part, version_id)

    deps = dependency.Graph()
    deps.add(version_entry, notice_entry)
    deps.validate_for(version_entry)

    if deps.is_stale(version_entry):
        notice_xml = notice_entry.read()
        version = Version(version_id, notice_xml.effective,
                          notice_xml.fr_citation)
        version_entry.write(version)
コード例 #29
0
def test_parents_of():
    final1 = Version(str(randrange(1000)), date(2002, 2, 2), Citation(1, 1))
    prop1 = Version(str(randrange(1000)), None, Citation(2, 2))
    final2 = Version(str(randrange(1000)), date(2004, 4, 4), Citation(3, 3))
    prop2 = Version('222', None, Citation(4, 4))
    prop3 = Version('333', None, Citation(6, 6))
    prop4 = Version('444', None, Citation(6, 6))

    correct_order = [final1, prop1, final2, prop2, prop3, prop4]
    for permutation in permutations(correct_order):
        assert list(sorted(permutation)) == correct_order
    paired = list(zip(correct_order, Version.parents_of(correct_order)))
    assert paired == [(final1, None), (prop1, final1), (final2, final1),
                      (prop2, final2), (prop3, final2), (prop4, final2)]
コード例 #30
0
def test_creates_version(monkeypatch):
    monkeypatch.setattr(proposal_versions, 'entry', Mock())
    notice = proposal_versions.entry.Notice.return_value.read.return_value
    notice.fr_citation = Citation(1, 2)
    notice.cfr_ref_pairs = [(11, 111), (11, 222), (22, 222), (22, 333)]

    result = CliRunner().invoke(proposal_versions.proposal_versions, ['dddd'])
    assert result.exception is None
    assert proposal_versions.entry.Notice.call_args == call('dddd')
    assert proposal_versions.entry.Version.call_args_list == [
        call(11, 111, 'dddd'),
        call(11, 222, 'dddd'),
        call(22, 222, 'dddd'),
        call(22, 333, 'dddd')
    ]
    write_args = proposal_versions.entry.Version.return_value.write.call_args
    assert write_args == call(Version('dddd', None, Citation(1, 2)))
コード例 #31
0
    def test_parents_of(self):
        final1 = Version(str(randrange(1000)),
                         date(2001, 1, 1), date(2002, 2, 2))
        prop1 = Version(str(randrange(1000)), date(2001, 6, 6), None)
        final2 = Version(str(randrange(1000)),
                         date(2003, 3, 3), date(2004, 4, 4))
        prop2 = Version('222', date(2003, 4, 4), None)
        prop3 = Version('333', date(2006, 6, 6), None)
        prop4 = Version('444', date(2006, 6, 6), None)

        correct_order = [final1, prop1, final2, prop2, prop3, prop4]
        for permutation in permutations(correct_order):
            self.assertEqual(sorted(permutation), correct_order)
        paired = list(zip(correct_order, Version.parents_of(correct_order)))
        self.assertEqual(
            paired,
            [(final1, None), (prop1, final1), (final2, final1),
             (prop2, final2), (prop3, final2), (prop4, final2)])
コード例 #32
0
def transform_notice(notice_xml):
    """The API has a different format for notices than the local XML. We'll
    need to convert and add appropriate fields"""
    as_dict = notice_xml.as_dict()
    as_dict['versions'] = {}
    for cfr_title, cfr_part in notice_xml.cfr_ref_pairs:
        version_dir = entry.Version(cfr_title, cfr_part)
        versions = [(version_dir / id).read() for id in version_dir]
        with_parents = zip(versions, Version.parents_of(versions))
        for version, parent in with_parents:
            if version.identifier == notice_xml.version_id and parent:
                as_dict['versions'][cfr_part] = {"left": parent.identifier,
                                                 "right": version.identifier}

    # @todo - SxS and footnotes aren't used outside of CFPB
    add_footnotes(as_dict, notice_xml.xml)
    if notice_xml.cfr_ref_pairs:
        process_sxs(as_dict, notice_xml.xml)
    return as_dict
コード例 #33
0
def fill_with_rules(cfr_title, cfr_part):
    """Fill in missing trees using data from rules. When a regulation tree
    cannot be derived through annual editions, it must be built by parsing the
    changes in final rules. This command builds those missing trees"""
    logger.info("Fill with rules - %s CFR %s", cfr_title, cfr_part)
    tree_dir = entry.Tree(cfr_title, cfr_part)
    version_dir = entry.Version(cfr_title, cfr_part)

    versions = [(version_dir / v).read() for v in version_dir]
    versions_with_parents = list(zip(versions, Version.parents_of(versions)))
    deps = dependencies(tree_dir, version_dir, versions_with_parents)

    derived = [(version.identifier, parent.identifier)
               for version, parent in versions_with_parents
               if is_derived(version.identifier, deps, tree_dir)]
    for version_id, parent_id in derived:
        deps.validate_for(tree_dir / version_id)
        if deps.is_stale(tree_dir / version_id):
            process(tree_dir, parent_id, version_id)
            deps.rebuild()
コード例 #34
0
ファイル: entry.py プロジェクト: cmc333333/regulations-parser
 def deserialize(self, content):
     return VersionStruct.from_json(content)
コード例 #35
0
 def deserialize(self, content):
     return VersionStruct.from_json(content.decode('utf-8'))