This is an automated email from the ASF dual-hosted git repository.

gstein pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/steve.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 9bf0c73  Tweaks for dealing with PersonDB
9bf0c73 is described below

commit 9bf0c7372f8b891bfaf6017ab9a3b9371854163c
Author: Greg Stein <[email protected]>
AuthorDate: Fri Feb 6 08:50:43 2026 -0600

    Tweaks for dealing with PersonDB
    
    The addition of PersonDB means there can (now) be two SQLite
    connections open to the database. This made create-election.py fail
    because both connections were trying to write (specifically, a
    transaction was started, which created a lock, with foreclosed the
    other connection).
    
    Fix: PersonDB now takes a DB instance in its constructor. There is a
    new class method to open() a filename for the DB and the PersonDB
    instance.
    
    TBD: the getattr/cursor attributes on the DB instance are not correct
    for both usages.
    
    * persondb.py: add the classmethod
    * create-election:
      - add #! to make this executable
      - revise transaction management
      - share the DB between the instances
      - hack in q_person cursor
    * asf-load-ldap, pages, check_coverage: switch to PersonDB.open()
---
 v3/server/bin/asf-load-ldap.py   |  2 +-
 v3/server/bin/create-election.py | 28 ++++++++++++++++++++++++----
 v3/server/pages.py               |  4 ++--
 v3/steve/persondb.py             | 11 +++++++++--
 v3/tests/check_coverage.py       |  2 +-
 5 files changed, 37 insertions(+), 10 deletions(-)

diff --git a/v3/server/bin/asf-load-ldap.py b/v3/server/bin/asf-load-ldap.py
index d5faefb..ab4ba46 100755
--- a/v3/server/bin/asf-load-ldap.py
+++ b/v3/server/bin/asf-load-ldap.py
@@ -39,7 +39,7 @@ LDAP_ATTR = 'memberUid'
 
 @asfpy.stopwatch.Stopwatch()
 def main():
-    pdb = steve.persondb.PersonDB(DB_FNAME)
+    pdb = steve.persondb.PersonDB.open(DB_FNAME)
     # Reach into PDB for the CONN, and start a transaction for all
     # of the inserts we will perform. (rather than default auto-commit)
     pdb.db.conn.execute('BEGIN TRANSACTION')
diff --git a/v3/server/bin/create-election.py b/v3/server/bin/create-election.py
old mode 100644
new mode 100755
index d3235f1..c922dfd
--- a/v3/server/bin/create-election.py
+++ b/v3/server/bin/create-election.py
@@ -1,3 +1,5 @@
+#!/usr/bin/env python3
+
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -32,6 +34,7 @@ DB_FNAME = THIS_DIR.parent / 'steve.db'
 # Supported vote types
 VALID_VTYPES = {'yna', 'stv'}
 
+
 def parse_datetime(dt_str):
     """Parse ISO datetime string to Unix timestamp."""
     if not dt_str:
@@ -39,6 +42,7 @@ 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:
@@ -51,6 +55,7 @@ def validate_issue(issue):
             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)
@@ -76,9 +81,12 @@ def main(yaml_file):
     if eligible_voters != 'members':
         raise ValueError("Only 'members' is supported for eligible_voters")
 
+    ### revising how we manage the two database instances and their
+    ### 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
@@ -95,20 +103,32 @@ def main(yaml_file):
             )
             _LOGGER.info(f'Added issue[I:{iid}] to election[E:{election.eid}]')
 
+        # Open a PersonDB using the existing DB from the Election
+        pdb = steve.persondb.PersonDB(election.db)
+
+        ### HACK: we opened PDB using the existing DB from the Election.
+        ### It does not have the cursors specific to PersonDB. For now,
+        ### hack the bugger in.
+        ### q_person: SELECT * FROM person ORDER BY pid
+        pdb.q_person = pdb.db.cursor_for('SELECT * FROM person ORDER BY pid')
+
         # Add voters: All persons in persondb to all issues
         all_persons = pdb.list_persons()
         for person in all_persons:
             election.add_voter(person.pid)
         _LOGGER.info(f'Added {len(all_persons)} voters to 
election[E:{election.eid}]')
 
-        pdb.db.conn.execute('COMMIT')
+        ### we aren't doing transactions right now. omit this.
+        #pdb.db.conn.execute('COMMIT')
         _LOGGER.info(f'Election[E:{election.eid}] fully created from 
{yaml_file}')
 
     except Exception as e:
-        pdb.db.conn.execute('ROLLBACK')
+        ### we aren't doing transactions right now. omit this.
+        #pdb.db.conn.execute('ROLLBACK')
         _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..65f7683 100644
--- a/v3/server/pages.py
+++ b/v3/server/pages.py
@@ -235,7 +235,7 @@ async def admin_page():
     ### "me" because of authz access to manage issues.
 
     ### should open/keep a PersonDB instance in the APP
-    pdb = steve.persondb.PersonDB(DB_FNAME)
+    pdb = steve.persondb.PersonDB.open(DB_FNAME)
     try:
         me = pdb.get_person(result.uid)
     except steve.persondb.PersonNotFound:
@@ -344,7 +344,7 @@ async def do_open_endpoint(election):
     ### check authz
 
     ### should open/keep a PersonDB instance in the APP
-    pdb = steve.persondb.PersonDB(DB_FNAME)
+    pdb = steve.persondb.PersonDB.open(DB_FNAME)
 
     # Open the Election.
     election.open(pdb)
diff --git a/v3/steve/persondb.py b/v3/steve/persondb.py
index a87fe17..c324346 100644
--- a/v3/steve/persondb.py
+++ b/v3/steve/persondb.py
@@ -24,8 +24,15 @@ QUERIES = THIS_DIR.parent / 'queries.yaml'
 
 
 class PersonDB:
-    def __init__(self, db_fname):
-        self.db = asfpy.db.DB(db_fname, yaml_fname=QUERIES, 
yaml_section='person')
+
+    @classmethod
+    def open(cls, db_fname):
+        return cls(asfpy.db.DB(db_fname,
+                               yaml_fname=QUERIES,
+                               yaml_section='person'))
+
+    def __init__(self, db):
+        self.db = db
 
     def __getattr__(self, name):
         "Proxy the cursors."
diff --git a/v3/tests/check_coverage.py b/v3/tests/check_coverage.py
index 766dbd5..d805275 100755
--- a/v3/tests/check_coverage.py
+++ b/v3/tests/check_coverage.py
@@ -54,7 +54,7 @@ def touch_every_line():
 
     _ = e.get_metadata()  # while EDITABLE
 
-    pdb = steve.persondb.PersonDB(TESTING_DB)
+    pdb = steve.persondb.PersonDB.open(TESTING_DB)
     pdb.add_person('alice', 'Alice', '[email protected]')
     pdb.add_person('bob', None, '[email protected]')
     pdb.add_person('carlos', 'Carlos', '[email protected]')

Reply via email to