civics-cdf-validator 1.61.dev4__tar.gz → 1.61.dev6__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {civics_cdf_validator-1.61.dev4/civics_cdf_validator.egg-info → civics_cdf_validator-1.61.dev6}/PKG-INFO +1 -1
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6/civics_cdf_validator.egg-info}/PKG-INFO +1 -1
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/rules.py +57 -5
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/version.py +1 -1
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/CONTRIBUTING.md +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/LICENSE-2.0.txt +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/MANIFEST.in +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/README.md +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/__init__.py +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/base.py +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/civics_cdf_validator.egg-info/SOURCES.txt +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/civics_cdf_validator.egg-info/dependency_links.txt +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/civics_cdf_validator.egg-info/entry_points.txt +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/civics_cdf_validator.egg-info/requires.txt +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/civics_cdf_validator.egg-info/top_level.txt +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/gpunit_rules.py +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/loggers.py +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/office_utils.py +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/setup.cfg +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/setup.py +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/stats.py +0 -0
- {civics_cdf_validator-1.61.dev4 → civics_cdf_validator-1.61.dev6}/validator.py +0 -0
|
@@ -141,6 +141,13 @@ _WINNER_POST_ELECTION_STATUSES = frozenset([
|
|
|
141
141
|
])
|
|
142
142
|
|
|
143
143
|
|
|
144
|
+
def _is_xml_true(element):
|
|
145
|
+
return (
|
|
146
|
+
element_has_text(element)
|
|
147
|
+
and element.text.strip().lower() in _XML_TRUE_VALUES
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
144
151
|
def _get_office_roles(element, is_post_office_split_feed=False):
|
|
145
152
|
if is_post_office_split_feed:
|
|
146
153
|
return [element.text for element in element.findall("Role")]
|
|
@@ -1624,6 +1631,50 @@ class DuplicateContestNames(base.BaseRule):
|
|
|
1624
1631
|
raise loggers.ElectionError(error_log)
|
|
1625
1632
|
|
|
1626
1633
|
|
|
1634
|
+
class DuplicateBallotTitleSeatPair(base.BaseRule):
|
|
1635
|
+
"""Checks that each English (BallotTitle, Seat) combination is unique.
|
|
1636
|
+
|
|
1637
|
+
Adds Warning/Error if duplicate English (BallotTitle, Seat) combinations are
|
|
1638
|
+
found.
|
|
1639
|
+
"""
|
|
1640
|
+
|
|
1641
|
+
def elements(self):
|
|
1642
|
+
return ["ContestCollection"]
|
|
1643
|
+
|
|
1644
|
+
def check(self, element):
|
|
1645
|
+
error_log = []
|
|
1646
|
+
contest_elements = element.findall("Contest")
|
|
1647
|
+
contests_by_title_and_seat = collections.defaultdict(list)
|
|
1648
|
+
|
|
1649
|
+
for contest in contest_elements:
|
|
1650
|
+
ballot_title_element = get_language_to_text_map(
|
|
1651
|
+
contest.find("BallotTitle")
|
|
1652
|
+
)
|
|
1653
|
+
english_title = ballot_title_element.get("en")
|
|
1654
|
+
seat_element = contest.find("Seat")
|
|
1655
|
+
|
|
1656
|
+
ballot_title = english_title[0].strip() if english_title else ""
|
|
1657
|
+
seat = seat_element.text.strip() if element_has_text(seat_element) else ""
|
|
1658
|
+
|
|
1659
|
+
if not ballot_title:
|
|
1660
|
+
continue
|
|
1661
|
+
|
|
1662
|
+
ballot_title_and_seat = (ballot_title, seat)
|
|
1663
|
+
contests_by_title_and_seat[ballot_title_and_seat].append(contest)
|
|
1664
|
+
|
|
1665
|
+
for ballot_title_and_seat, contests in contests_by_title_and_seat.items():
|
|
1666
|
+
if len(contests) > 1:
|
|
1667
|
+
ballot_title, seat = ballot_title_and_seat
|
|
1668
|
+
error_message = (
|
|
1669
|
+
"Multiple Contests found with the same BallotTitle"
|
|
1670
|
+
f" ('{ballot_title}') and Seat ('{seat}')."
|
|
1671
|
+
)
|
|
1672
|
+
error_log.append(loggers.LogEntry(error_message, contests))
|
|
1673
|
+
|
|
1674
|
+
if error_log:
|
|
1675
|
+
raise loggers.ElectionError(error_log)
|
|
1676
|
+
|
|
1677
|
+
|
|
1627
1678
|
class UniqueStableID(base.TreeRule):
|
|
1628
1679
|
"""Check that every stableID is unique.
|
|
1629
1680
|
|
|
@@ -4716,6 +4767,10 @@ class FeedInactiveDateIsLatestDate(base.BaseRule):
|
|
|
4716
4767
|
return ["Feed"]
|
|
4717
4768
|
|
|
4718
4769
|
def check(self, element):
|
|
4770
|
+
# Skip this rule for test feeds.
|
|
4771
|
+
if _is_xml_true(element.find("IsTest")):
|
|
4772
|
+
return
|
|
4773
|
+
|
|
4719
4774
|
if element_has_text(element.find("FeedInactiveDate")):
|
|
4720
4775
|
feed_inactive_date = base.PartialDate.init_partial_date(
|
|
4721
4776
|
element.find("FeedInactiveDate").text
|
|
@@ -5404,11 +5459,7 @@ class ValidateIncludeInAggregationBallotSelections(base.BaseRule):
|
|
|
5404
5459
|
|
|
5405
5460
|
included_selections = []
|
|
5406
5461
|
for selection in all_selections:
|
|
5407
|
-
|
|
5408
|
-
if (
|
|
5409
|
-
element_has_text(included_in_aggregation_element)
|
|
5410
|
-
and included_in_aggregation_element.text in _XML_TRUE_VALUES
|
|
5411
|
-
):
|
|
5462
|
+
if _is_xml_true(selection.find("IncludedInAggregation")):
|
|
5412
5463
|
included_selections.append(selection)
|
|
5413
5464
|
if not included_selections:
|
|
5414
5465
|
return
|
|
@@ -5531,6 +5582,7 @@ ELECTION_RULES = COMMON_RULES + (
|
|
|
5531
5582
|
ContestStartDateContainsCorrespondingEndDate,
|
|
5532
5583
|
CorrectCandidateSelectionCount,
|
|
5533
5584
|
DateStatusMatches,
|
|
5585
|
+
DuplicateBallotTitleSeatPair,
|
|
5534
5586
|
DuplicateContestNames,
|
|
5535
5587
|
DuplicatedPartyAbbreviation,
|
|
5536
5588
|
DuplicatedPartyName,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|