civics-cdf-validator 1.57.dev8__tar.gz → 1.57.dev10__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.57.dev8/civics_cdf_validator.egg-info → civics_cdf_validator-1.57.dev10}/PKG-INFO +1 -1
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/base.py +16 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10/civics_cdf_validator.egg-info}/PKG-INFO +1 -1
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/rules.py +9 -56
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/version.py +1 -1
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/CONTRIBUTING.md +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/LICENSE-2.0.txt +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/MANIFEST.in +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/README.md +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/__init__.py +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/civics_cdf_validator.egg-info/SOURCES.txt +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/civics_cdf_validator.egg-info/dependency_links.txt +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/civics_cdf_validator.egg-info/entry_points.txt +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/civics_cdf_validator.egg-info/requires.txt +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/civics_cdf_validator.egg-info/top_level.txt +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/gpunit_rules.py +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/loggers.py +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/office_utils.py +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/setup.cfg +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/setup.py +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/stats.py +0 -0
- {civics_cdf_validator-1.57.dev8 → civics_cdf_validator-1.57.dev10}/validator.py +0 -0
|
@@ -16,6 +16,7 @@ limitations under the License.
|
|
|
16
16
|
|
|
17
17
|
from __future__ import print_function
|
|
18
18
|
|
|
19
|
+
from collections.abc import Set
|
|
19
20
|
import datetime
|
|
20
21
|
import functools
|
|
21
22
|
import re
|
|
@@ -93,6 +94,21 @@ class BaseRule(SchemaHandler):
|
|
|
93
94
|
def setup(self):
|
|
94
95
|
"""Perform any rule specific setup before checking."""
|
|
95
96
|
|
|
97
|
+
def get_element_names_for_types(self, element_types: Set[str]) -> set[str]:
|
|
98
|
+
element_names = set()
|
|
99
|
+
for _, element in etree.iterwalk(self.schema_tree):
|
|
100
|
+
tag = self.strip_schema_ns(element)
|
|
101
|
+
if (
|
|
102
|
+
tag == "element"
|
|
103
|
+
and element.get("type") in element_types
|
|
104
|
+
and element.get("name") is not None
|
|
105
|
+
):
|
|
106
|
+
element_names.add(element.get("name"))
|
|
107
|
+
return element_names
|
|
108
|
+
|
|
109
|
+
def get_element_names_for_type(self, element_type: str) -> set[str]:
|
|
110
|
+
return self.get_element_names_for_types({element_type})
|
|
111
|
+
|
|
96
112
|
|
|
97
113
|
class TreeRule(BaseRule):
|
|
98
114
|
"""Rule that checks entire tree."""
|
|
@@ -34,6 +34,7 @@ from six.moves.urllib.parse import urlparse
|
|
|
34
34
|
|
|
35
35
|
_PARTY_LEADERSHIP_TYPES = ["party-leader-id", "party-chair-id"]
|
|
36
36
|
_INDEPENDENT_PARTY_NAMES = frozenset(["independent", "nonpartisan"])
|
|
37
|
+
_IDREF_TYPES = frozenset(["xs:IDREF", "xs:IDREFS"])
|
|
37
38
|
# The set of external identifiers that contain references to other entities.
|
|
38
39
|
_IDREF_EXTERNAL_IDENTIFIERS = frozenset(
|
|
39
40
|
["jurisdiction-id"] + _PARTY_LEADERSHIP_TYPES
|
|
@@ -49,7 +50,7 @@ _CONTEST_STAGE_TYPES = frozenset([
|
|
|
49
50
|
"official",
|
|
50
51
|
"unnamed",
|
|
51
52
|
])
|
|
52
|
-
|
|
53
|
+
_INTERNATIONALIZED_TEXT_ELEMENTS_WITH_ONLY_ONE_TEXT_PER_LANGUAGE = [
|
|
53
54
|
# go/keep-sorted start
|
|
54
55
|
"BallotName",
|
|
55
56
|
"BallotSubTitle",
|
|
@@ -441,9 +442,7 @@ class EmptyText(base.BaseRule):
|
|
|
441
442
|
return ["Text"]
|
|
442
443
|
|
|
443
444
|
def check(self, element):
|
|
444
|
-
if
|
|
445
|
-
element.text is None and element.get("language") is not None
|
|
446
|
-
):
|
|
445
|
+
if element.text is None or not element.text.strip():
|
|
447
446
|
raise loggers.ElectionError.from_message("Text is empty", element)
|
|
448
447
|
|
|
449
448
|
|
|
@@ -451,18 +450,7 @@ class EmptyString(base.BaseRule):
|
|
|
451
450
|
"""Check that string fields are not empty or strictly whitespace."""
|
|
452
451
|
|
|
453
452
|
def elements(self):
|
|
454
|
-
"
|
|
455
|
-
string_elements = []
|
|
456
|
-
for _, element in etree.iterwalk(self.schema_tree):
|
|
457
|
-
tag = self.strip_schema_ns(element)
|
|
458
|
-
if (
|
|
459
|
-
tag
|
|
460
|
-
and tag == "element"
|
|
461
|
-
and element.get("type") == "xs:string"
|
|
462
|
-
and element.get("name") is not None
|
|
463
|
-
):
|
|
464
|
-
string_elements.append(element.get("name"))
|
|
465
|
-
return string_elements
|
|
453
|
+
return list(self.get_element_names_for_type("xs:string"))
|
|
466
454
|
|
|
467
455
|
# pylint: disable=g-explicit-length-test
|
|
468
456
|
def check(self, element):
|
|
@@ -961,15 +949,7 @@ class UniqueLabel(base.BaseRule):
|
|
|
961
949
|
self.labels = set()
|
|
962
950
|
|
|
963
951
|
def elements(self):
|
|
964
|
-
|
|
965
|
-
for _, element in etree.iterwalk(self.schema_tree):
|
|
966
|
-
tag = self.strip_schema_ns(element)
|
|
967
|
-
if tag == "element":
|
|
968
|
-
elem_type = element.get("type")
|
|
969
|
-
if elem_type == "InternationalizedText":
|
|
970
|
-
if element.get("name") not in eligible_elements:
|
|
971
|
-
eligible_elements.append(element.get("name"))
|
|
972
|
-
return eligible_elements
|
|
952
|
+
return list(self.get_element_names_for_type("InternationalizedText"))
|
|
973
953
|
|
|
974
954
|
def check(self, element):
|
|
975
955
|
element_label = element.get("label")
|
|
@@ -3939,7 +3919,7 @@ class MultipleInternationalizedTextWithSameLanguageCode(base.BaseRule):
|
|
|
3939
3919
|
"""Checks for multiple InternationalizedText with the same language code."""
|
|
3940
3920
|
|
|
3941
3921
|
def elements(self):
|
|
3942
|
-
return
|
|
3922
|
+
return _INTERNATIONALIZED_TEXT_ELEMENTS_WITH_ONLY_ONE_TEXT_PER_LANGUAGE
|
|
3943
3923
|
|
|
3944
3924
|
def check(self, element):
|
|
3945
3925
|
language_map = get_language_to_text_map(element)
|
|
@@ -3952,22 +3932,10 @@ class MultipleInternationalizedTextWithSameLanguageCode(base.BaseRule):
|
|
|
3952
3932
|
|
|
3953
3933
|
|
|
3954
3934
|
class AllInternationalizedTextHaveEnVersion(base.BaseRule):
|
|
3955
|
-
"""Checks for
|
|
3935
|
+
"""Checks for InternationalizedText elements missing an English version."""
|
|
3956
3936
|
|
|
3957
3937
|
def elements(self):
|
|
3958
|
-
return
|
|
3959
|
-
"BallotName",
|
|
3960
|
-
"Directions",
|
|
3961
|
-
"BallotSubTitle",
|
|
3962
|
-
"BallotTitle",
|
|
3963
|
-
"Name",
|
|
3964
|
-
"InternationalizedName",
|
|
3965
|
-
"InternationalizedAbbreviation",
|
|
3966
|
-
"Alias",
|
|
3967
|
-
"FullName",
|
|
3968
|
-
"Profession",
|
|
3969
|
-
"Title",
|
|
3970
|
-
]
|
|
3938
|
+
return list(self.get_element_names_for_type("InternationalizedText"))
|
|
3971
3939
|
|
|
3972
3940
|
def check(self, element):
|
|
3973
3941
|
language_map = get_language_to_text_map(element)
|
|
@@ -4518,29 +4486,14 @@ class UnreferencedEntitiesBase(base.TreeRule):
|
|
|
4518
4486
|
self.top_level_entity_types = top_level_entity_types
|
|
4519
4487
|
self.warned_entity_types = warned_entity_types
|
|
4520
4488
|
|
|
4521
|
-
def _get_idref_elements(self):
|
|
4522
|
-
"""Returns the names of all XML elements in the schema of type IDREF or IDREFS."""
|
|
4523
|
-
|
|
4524
|
-
idref_elements = set()
|
|
4525
|
-
for _, element in etree.iterwalk(self.schema_tree):
|
|
4526
|
-
tag = self.strip_schema_ns(element)
|
|
4527
|
-
if (
|
|
4528
|
-
tag
|
|
4529
|
-
and tag == "element"
|
|
4530
|
-
and element.get("type") in ("xs:IDREF", "xs:IDREFS")
|
|
4531
|
-
):
|
|
4532
|
-
idref_elements.add(element.get("name"))
|
|
4533
|
-
return idref_elements
|
|
4534
|
-
|
|
4535
4489
|
def _gather_referenced_entities(self):
|
|
4536
4490
|
"""Create a set of all entities referenced by either IDREF(S) elements or external identifiers."""
|
|
4537
|
-
|
|
4538
|
-
idref_elements = self._get_idref_elements()
|
|
4539
4491
|
referenced_entities = set()
|
|
4540
4492
|
for external_id_type in _IDREF_EXTERNAL_IDENTIFIERS:
|
|
4541
4493
|
referenced_entities.update(
|
|
4542
4494
|
get_external_id_values(self.election_tree, external_id_type)
|
|
4543
4495
|
)
|
|
4496
|
+
idref_elements = self.get_element_names_for_types(_IDREF_TYPES)
|
|
4544
4497
|
for _, element in etree.iterwalk(self.election_tree):
|
|
4545
4498
|
tag = self.strip_schema_ns(element)
|
|
4546
4499
|
if tag and tag in idref_elements:
|
|
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
|