From 919373210072cbb0798c00af8a47451a00028ccd Mon Sep 17 00:00:00 2001 From: tison Date: Wed, 4 Feb 2026 22:53:22 +0800 Subject: [PATCH 1/4] Fix load-fakedata.py Signed-off-by: tison --- v3/server/bin/load-fakedata.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/v3/server/bin/load-fakedata.py b/v3/server/bin/load-fakedata.py index 82ed768..096230f 100755 --- a/v3/server/bin/load-fakedata.py +++ b/v3/server/bin/load-fakedata.py @@ -59,11 +59,7 @@ def gen_election(owner_pid, issue_count=10): description = FAKE.paragraph() vtype = 'yna' ### something else? kv = None ### something else? - - ### grr. this should be internal - iid = steve.crypto.create_id() - e.add_issue(iid, title, description, vtype, kv) - _LOGGER.info(f'[E:{e.eid}]: created issue[I:{iid}]: "{title}"') + e.add_issue(title, description, vtype, kv) def random_owner(): From ad7b746a316c71e35aad67dbb4a6df92f417fcc5 Mon Sep 17 00:00:00 2001 From: tison Date: Thu, 5 Feb 2026 10:51:12 +0800 Subject: [PATCH 2/4] Fixup CI Signed-off-by: tison --- .github/workflows/linting.yml | 3 ++- .github/workflows/type-tests.yml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index b4f242e..8435610 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -30,7 +30,8 @@ jobs: - name: Install dependencies working-directory: v3 run: | - sudo apt-get install libldap2-dev libsasl2-dev + sudo apt-get update -y + sudo apt-get install -y libldap2-dev libsasl2-dev uv sync --all-extras --dev - name: Check with ruff working-directory: v3 diff --git a/.github/workflows/type-tests.yml b/.github/workflows/type-tests.yml index 756edd4..5d36a29 100644 --- a/.github/workflows/type-tests.yml +++ b/.github/workflows/type-tests.yml @@ -30,7 +30,8 @@ jobs: - name: Install dependencies working-directory: v3 # Set the working directory to v3 where pyproject.toml is located run: | - sudo apt-get install libldap2-dev libsasl2-dev + sudo apt-get update -y + sudo apt-get install -y libldap2-dev libsasl2-dev uv sync --all-extras --dev - name: Type testing with mypy working-directory: v3 # Ensure mypy runs in the correct directory From b1e3c5336d6a866c31519a2ec05acaba4bfaec99 Mon Sep 17 00:00:00 2001 From: tison Date: Thu, 5 Feb 2026 10:53:14 +0800 Subject: [PATCH 3/4] run formatter Signed-off-by: tison --- v3/server/bin/create-election.py | 24 +++++++++++++++++------- v3/server/pages.py | 8 +++++--- v3/steve/election.py | 8 ++------ v3/steve/vtypes/stv.py | 17 ++++++++++------- v3/tests/run_stv.py | 4 ++-- 5 files changed, 36 insertions(+), 25 deletions(-) diff --git a/v3/server/bin/create-election.py b/v3/server/bin/create-election.py index d3235f1..3c302a9 100644 --- a/v3/server/bin/create-election.py +++ b/v3/server/bin/create-election.py @@ -32,6 +32,7 @@ # Supported vote types VALID_VTYPES = {'yna', 'stv'} + def parse_datetime(dt_str): """Parse ISO datetime string to Unix timestamp.""" if not dt_str: @@ -39,18 +40,22 @@ def parse_datetime(dt_str): dt = datetime.datetime.fromisoformat(dt_str) return int(dt.timestamp()) + def validate_issue(issue): """Validate an issue dict from YAML.""" if 'vtype' not in issue or issue['vtype'] not in VALID_VTYPES: - raise ValueError(f"Invalid vtype: {issue.get('vtype')}") + raise ValueError(f'Invalid vtype: {issue.get("vtype")}') if issue['vtype'] == 'stv': kv = issue.get('kv', {}) if not all(k in kv for k in ['version', 'labelmap', 'seats']): - raise ValueError("STV issue missing required kv fields: version, labelmap, seats") + raise ValueError( + 'STV issue missing required kv fields: version, labelmap, seats' + ) if not isinstance(kv['seats'], int) or kv['seats'] <= 0: - raise ValueError("STV seats must be a positive integer") + raise ValueError('STV seats must be a positive integer') return issue + def main(yaml_file): with open(yaml_file, 'r') as f: data = yaml.safe_load(f) @@ -64,7 +69,7 @@ def main(yaml_file): close_at = parse_datetime(election_data.get('close_at')) if not title or not owner_pid: - raise ValueError("Election must have title and owner_pid") + raise ValueError('Election must have title and owner_pid') # Extract issues issues = data.get('issues', []) @@ -82,8 +87,12 @@ def main(yaml_file): try: # Create election - election = steve.election.Election.create(DB_FNAME, title, owner_pid, authz, open_at, close_at) - _LOGGER.info(f'Created election[E:{election.eid}]: "{title}" by owner "{owner_pid}"') + election = steve.election.Election.create( + DB_FNAME, title, owner_pid, authz, open_at, close_at + ) + _LOGGER.info( + f'Created election[E:{election.eid}]: "{title}" by owner "{owner_pid}"' + ) # Add issues for issue_data in issues: @@ -91,7 +100,7 @@ def main(yaml_file): issue_data['title'], issue_data.get('description'), issue_data['vtype'], - issue_data.get('kv') if issue_data['vtype'] == 'stv' else None + issue_data.get('kv') if issue_data['vtype'] == 'stv' else None, ) _LOGGER.info(f'Added issue[I:{iid}] to election[E:{election.eid}]') @@ -109,6 +118,7 @@ def main(yaml_file): _LOGGER.error(f'Failed to create election from {yaml_file}: {e}') raise + if __name__ == '__main__': logging.basicConfig(level=logging.INFO) diff --git a/v3/server/pages.py b/v3/server/pages.py index 55d98c5..36db875 100644 --- a/v3/server/pages.py +++ b/v3/server/pages.py @@ -308,7 +308,7 @@ async def manage_stv_page(election, issue): result.seats = kv.seats ### list of candidates. see KV.LABELMAP - #result.count = len(result.candidates) + # result.count = len(result.candidates) return result @@ -327,8 +327,10 @@ async def do_create_endpoint(): # Create the Election. election = steve.election.Election.create(DB_FNAME, form.title, result.uid) - _LOGGER.info(f'User[U:{result.uid}] created election[E:{election.eid}];' - f' title: "{form.title}"') + _LOGGER.info( + f'User[U:{result.uid}] created election[E:{election.eid}];' + f' title: "{form.title}"' + ) await flash_success(f'Created election: {form.title}') # Go to the management page for the new Election. diff --git a/v3/steve/election.py b/v3/steve/election.py index 2311aa5..06b3c04 100644 --- a/v3/steve/election.py +++ b/v3/steve/election.py @@ -196,7 +196,6 @@ def get_metadata(self): closed=md.closed, ### should we process this? open_at=md.open_at, ### should we process this? close_at=md.close_at, ### should we process this? - state=self._compute_state(md), ) @@ -235,9 +234,7 @@ def edit_issue(self, iid, title, description, vtype, kv): assert self.is_editable() assert vtype in vtypes.TYPES - self.c_edit_issue.perform( - title, description, vtype, self.kv2json(kv), iid - ) + self.c_edit_issue.perform(title, description, vtype, self.kv2json(kv), iid) # If the issue didn't exist, we updated nothing. if self.c_edit_issue.rowcount == 0: @@ -447,8 +444,7 @@ def create( while True: eid = crypto.create_id() try: - db.c_create.perform(eid, title, owner_pid, - authz, open_at, close_at) + db.c_create.perform(eid, title, owner_pid, authz, open_at, close_at) break except sqlite3.IntegrityError: _LOGGER.debug('EID conflict(!!) ... trying again.') diff --git a/v3/steve/vtypes/stv.py b/v3/steve/vtypes/stv.py index 55c6af1..af79c4a 100644 --- a/v3/steve/vtypes/stv.py +++ b/v3/steve/vtypes/stv.py @@ -40,7 +40,7 @@ def load_stv(): def tally(votestrings, kv): """ Run the STV tally process. - + votestrings: List of strings, each representing a voter's preferences as comma-separated labels (e.g., 'a,b,c' for votes in order of preference). Labels must match keys in kv['labelmap']. kv: Dict containing STV configuration. @@ -48,21 +48,24 @@ def tally(votestrings, kv): - 'labelmap': Dict mapping single-character labels to candidate names (e.g., {'a': 'Alice'}). - 'seats': Integer number of seats to elect. """ - + # kv['labelmap'] should be: LABEL: NAME # for example: { 'a': 'John Doe', } labelmap = kv['labelmap'] - + seats = kv['seats'] - + # Remap all votestrings from comma-separated label strings into sequences of NAMEs. # Split on commas, strip whitespace, and filter out empty parts. - votes = [[labelmap[label.strip()] for label in v.split(',') if label.strip()] for v in votestrings] - + votes = [ + [labelmap[label.strip()] for label in v.split(',') if label.strip()] + for v in votestrings + ] + # Use sorted names for reproducible ordering. names = sorted(labelmap.values()) results = stv_tool.run_stv(names, votes, seats) - + human = '\n'.join( f'{c.name:40}{" " if c.status == stv_tool.ELECTED else " not "}elected' for c in results.l diff --git a/v3/tests/run_stv.py b/v3/tests/run_stv.py index 09912ee..53a2b5a 100755 --- a/v3/tests/run_stv.py +++ b/v3/tests/run_stv.py @@ -37,12 +37,12 @@ def main(mtgdir): assert os.path.exists(labelfile) labelmap = stv_tool.read_labelmap(labelfile) - newformat = (len(next(iter(labelmap))) > 1) # keys like "a" or "aa"? + newformat = len(next(iter(labelmap))) > 1 # keys like "a" or "aa"? votes = stv_tool.read_votefile(rawfile, newformat) # Rebuild the list of label-lists into a comma-separated votestring # for the STV tally function. - votestrings = [ ','.join(v) for v in votes ] + votestrings = [','.join(v) for v in votes] kv = { 'version': 1, From 7a0a94afcdbf215fc1fdb5b5190ab304c6a861db Mon Sep 17 00:00:00 2001 From: tison Date: Sat, 7 Feb 2026 11:04:51 +0800 Subject: [PATCH 4/4] more format Signed-off-by: tison --- v3/server/bin/create-election.py | 8 ++++---- v3/steve/persondb.py | 5 +---- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/v3/server/bin/create-election.py b/v3/server/bin/create-election.py index 15a257a..9b44718 100755 --- a/v3/server/bin/create-election.py +++ b/v3/server/bin/create-election.py @@ -87,8 +87,8 @@ def main(yaml_file): ### connections. no transactions for now. partial Elections, and ### issues are fine for now. # Start transaction for safety - #pdb = steve.persondb.PersonDB(DB_FNAME) - #pdb.db.conn.execute('BEGIN TRANSACTION') + # pdb = steve.persondb.PersonDB(DB_FNAME) + # pdb.db.conn.execute('BEGIN TRANSACTION') try: # Create election @@ -125,12 +125,12 @@ def main(yaml_file): _LOGGER.info(f'Added {len(all_persons)} voters to election[E:{election.eid}]') ### we aren't doing transactions right now. omit this. - #pdb.db.conn.execute('COMMIT') + # pdb.db.conn.execute('COMMIT') _LOGGER.info(f'Election[E:{election.eid}] fully created from {yaml_file}') except Exception as e: ### we aren't doing transactions right now. omit this. - #pdb.db.conn.execute('ROLLBACK') + # pdb.db.conn.execute('ROLLBACK') _LOGGER.error(f'Failed to create election from {yaml_file}: {e}') raise diff --git a/v3/steve/persondb.py b/v3/steve/persondb.py index c324346..e5b8de1 100644 --- a/v3/steve/persondb.py +++ b/v3/steve/persondb.py @@ -24,12 +24,9 @@ class PersonDB: - @classmethod def open(cls, db_fname): - return cls(asfpy.db.DB(db_fname, - yaml_fname=QUERIES, - yaml_section='person')) + return cls(asfpy.db.DB(db_fname, yaml_fname=QUERIES, yaml_section='person')) def __init__(self, db): self.db = db