Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ on:
- cron: "30 23 * * 1" # 2330 UTC Every Monday

env:
PYTHON_VERSION: "3.9.5"
PYTHON_VERSION: 3.9
POETRY_PATH: "$HOME/.poetry/bin"

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:
types: [closed]

env:
PYTHON_VERSION: "3.9.5"
PYTHON_VERSION: 3.9
POETRY_PATH: "$HOME/.poetry/bin"

jobs:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ ElectionGuard supports a variety of use cases. The Primary use case is to genera

## 💻 Requirements

- [Python 3.9.5](https://www.python.org/downloads/) is <ins>**required**</ins> to develop this SDK. If developer uses multiple versions of python, [pyenv](https://github.com/pyenv/pyenv) is suggested to assist version management.
- [Python 3.9](https://www.python.org/downloads/) is <ins>**required**</ins> to develop this SDK. If developer uses multiple versions of python, [pyenv](https://github.com/pyenv/pyenv) is suggested to assist version management.
- [GNU Make](https://www.gnu.org/software/make/manual/make.html) is used to simplify the commands and GitHub Actions. This approach is recommended to simplify the command line experience. This is built in for MacOS and Linux. For Windows, setup is simpler with [Chocolatey](https://chocolatey.org/install) and installing the provided [make package](https://chocolatey.org/packages/make). The other Windows option is [manually installing make](http://gnuwin32.sourceforge.net/packages/make.htm).
- [Gmpy2](https://gmpy2.readthedocs.io/en/latest/) is used for [Arbitrary-precision arithmetic](https://en.wikipedia.org/wiki/Arbitrary-precision_arithmetic) which
has its own [installation requirements (native C libraries)](https://gmpy2.readthedocs.io/en/latest/intro.html#installation) on Linux and MacOS. **⚠️ Note:** _This is not required for Windows since the gmpy2 precompiled libraries are provided._
Expand Down
67 changes: 66 additions & 1 deletion src/electionguard/manifest.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ def crypto_hash(self) -> ElementModQ:
return hash


# pylint: disable=super-init-not-called
@dataclass(eq=True, unsafe_hash=True)
class Language(CryptoHashable):
"""
Expand All @@ -117,6 +118,16 @@ class Language(CryptoHashable):
value: str
language: str = field(default="en")

# explicit `__init__` added as workaround for https://bugs.python.org/issue45081
# can potentially be removed with future python version >3.9.7
def __init__(
self,
value: str,
language: str = "en",
):
self.value = value
self.language = language

def crypto_hash(self) -> ElementModQ:
"""
A hash representation of the object
Expand All @@ -126,6 +137,7 @@ def crypto_hash(self) -> ElementModQ:
return hash


# pylint: disable=super-init-not-called
@dataclass(eq=True, unsafe_hash=True)
class InternationalizedText(CryptoHashable):
"""
Expand All @@ -135,6 +147,14 @@ class InternationalizedText(CryptoHashable):

text: List[Language] = field(default_factory=lambda: [])

# explicit `__init__` added as workaround for https://bugs.python.org/issue45081
# can potentially be removed with future python version >3.9.7
def __init__(
self,
text: List[Language] = None,
):
self.text = text if text else list()

def crypto_hash(self) -> ElementModQ:
"""
A hash representation of the object
Expand All @@ -144,6 +164,7 @@ def crypto_hash(self) -> ElementModQ:
return hash


# pylint: disable=super-init-not-called
@dataclass(eq=True, unsafe_hash=True)
class ContactInformation(CryptoHashable):
"""
Expand All @@ -156,6 +177,20 @@ class ContactInformation(CryptoHashable):
phone: Optional[List[AnnotatedString]] = field(default=None)
name: Optional[str] = field(default=None)

# explicit `__init__` added as workaround for https://bugs.python.org/issue45081
# can potentially be removed with future python version >3.9.7
def __init__(
self,
address_line: Optional[List[str]] = None,
email: Optional[List[AnnotatedString]] = None,
phone: Optional[List[AnnotatedString]] = None,
name: Optional[str] = None,
):
self.address_line = address_line
self.email = email
self.phone = phone
self.name = name

def crypto_hash(self) -> ElementModQ:
"""
A hash representation of the object
Expand Down Expand Up @@ -517,7 +552,7 @@ def selection_for(self, selection_id: str) -> Optional[SelectionDescription]:
return None


# pylint: disable=too-many-instance-attributes
# pylint: disable=too-many-instance-attributes,super-init-not-called
@dataclass(unsafe_hash=True)
class Manifest(CryptoHashable):
"""
Expand Down Expand Up @@ -546,6 +581,36 @@ class Manifest(CryptoHashable):
name: Optional[InternationalizedText] = field(default=None)
contact_information: Optional[ContactInformation] = field(default=None)

# explicit `__init__` added as workaround for https://bugs.python.org/issue45081
# can potentially be removed with future python version >3.9.7
def __init__(
self,
election_scope_id: str,
spec_version: str,
type: ElectionType,
start_date: datetime,
end_date: datetime,
geopolitical_units: List[GeopoliticalUnit],
parties: List[Party],
candidates: List[Candidate],
contests: List[ContestDescription],
ballot_styles: List[BallotStyle],
name: Optional[InternationalizedText] = None,
contact_information: Optional[ContactInformation] = None,
):
self.election_scope_id = election_scope_id
self.spec_version = spec_version
self.type = type
self.start_date = start_date
self.end_date = end_date
self.geopolitical_units = geopolitical_units
self.parties = parties
self.candidates = candidates
self.contests = contests
self.ballot_styles = ballot_styles
self.name = name
self.contact_information = contact_information

def __eq__(self, other: Any) -> bool:
return (
isinstance(other, Manifest)
Expand Down