Skip to content

API documentation

async pseudovote.service.startup()

Initialize app.

async pseudovote.service.shutdown()

Shut everything down as gracefully as possible.

class pseudovote.service.poll_choices(title='', min=0, max=1, choices=None, ordered=False)

Convenience data structure to keep those crazy regexes beside the poll options data itself.

class pseudovote.service.VoteRejectException(message)

Dedicated exception for vote processing to simplify the logic.

pseudovote.service.get_pseudonym_list(voter_count, word_list, cryptonyms=False, salt_amount=None)

Creating the randomized list of pseudonyms was initially the main feature of initial Uduloor version of pseudonymous voting routine, but it is currently provided here mostly for convenience. Ideally you should select the pseudonyms far away from the bulletin board service in order to avoid any manipulation of the votes. Selection process currently enables of selection pseudonyms and "salting" them with a number to create memorizable pairs of text and numbers following the pattern of user123. In a real polling situation you should provide pseudonyms separately and then maybe include hashed list of pseudonyms as gatekeeper for vote collecting mechanism to make sure it is not manipulated by spamming or similar.

pseudovote.service.announce_event(name, timestamp, channel, started=None)

Announce events to every client in channel.

pseudovote.service.announce_event_individual(name, timestamp, cq, channel, started=None)

Announce already past events for individual clients mostly on connecting the feed.

pseudovote.service.event_publisher(req, channel, cq, start, end, encrypt_ballots=False)

Each client will have this publisher loop that will self destruct on disconnect. If no clients are listening to specifig election feed any more, the channel itself will be removed.


Listens to database notifications and relays the messages to designated channels. There is one notfication service for all the votings in order to keep the connection pool minimal.

async pseudovote.service.subscribe_bulletin(req)

Bulletin board of incoming votes is an essential feature and is displayed based on token of a poll. The feed is provided as EventSource feed in JSON and includes also poll status announcements.


Convert name to a slug. Maybe should replace with dedicated slugify module.

async pseudovote.service.get_bulletin_token(req)

Coordinate available tokens with database.

async pseudovote.service.get_bulletin_name(req)

Coordinate available names with database.

pseudovote.service.data_state(label, data={}, token='?')

Content of data events about voting progress generated by the main voting process routine.

async pseudovote.service.start_voting(req)

Web entry point for creating a poll/an election.

pseudovote.service.conduct_voting_process(req, body=None)

Tha main voting process routine will run on server until the voting is over and will provide real time data feed in EventSource format on audit dashboard. The feed consists of JSON formatted notes about changes in poll status. It takes POST request body as imput, if no request body is provided it will attempt to catch up with feed of already existing poll based on token parameter of request. Technically poll can fail if create_poll is not reached or successfully executed, but after that the process will run on autopilot up the end of voting process. If the connection is terminally dropped for some reason, one can connect to public audit dashboard{token} or using JSON event feed to continue auditing the process, which will provide you the same data except sent e-mails report, which is currently specific to the viewpoint of the creator of the poll.

async pseudovote.service.create_poll(title=None, token=None, name=None, start_time=None, end_time=None, choices=None, voterhash_type=None, ballot_type=None, reject_multi=None, personal_ballot=None, limit_choices=None, reject_invalid=None, reject_unlisted=None, mute_unlisted=None, block_unlisted=None, limit_invalid=None, limit_unlisted=None, limit_multi=None, encrypt_ballots=None, voter_count=None)

Register a poll in database.

async pseudovote.service.provide_voterlist_to_bulletin(pseudo_list, voterhash_type=None, bulletin_id=None)

Create voterlist for the poll in case provide_voterlist has been selected among bulletin board restrictions. Otherwise the voterlist will be not recorded to database, except for emergency fallback (see encrypt_voterlist_under_embargo).

async pseudovote.service.encrypt_voterlist_under_embargo(pseudo_list, use_public_key, pubkey_id, bulletin_id)

Encrypting voterlist is done on demand with pgp public key provided at use_public_key in bulletin board access restrictions dialog or as a fallback when system breaks down for some reason. If voterlist is encrypted as a fallback, public key of the bulletin board system itself is used in order to decrypt the voterlist with private key after embargo, that is, when the election is over. Currently encrypting the voterlist is not proper feature of exemplified voting scheme, because encryping voterlist makes sense if it is done as completely separate process and maybe providing voterlist to bulletin board in already encrypted form (hashed pseydonyms and/or full encrypted voterlist to be decrypted after election is over).

async pseudovote.service.get_ballot_count(bulletin_id)

Report ballot count for a poll/election.

async pseudovote.service.collector(req)

Vote collector is a web page where votes are collected for single pre-defined election. Election status and bulletin board of incoming votes are displayed in real time to provide voter transparancy and hands on understanding of the process. Vote collector is the most critical part of the system from viewpoint of technical universality and has to be usable without Javascript or any other fancy web technology. Currently vote collector is somewhat tested against HTTPS capable versions of Lynx, Netscape Navigator and different versions Android/iPhone.

async pseudovote.service.votes_until_now(token=None, bulletin_id=None, start=None, end=None, encrypt_ballots=None)

Displays bulletin board in TEXT format up to current moment. This is used as an easy way to display bulletin board history in vote collector TEXTAREA without extra work on client side, maybe ideally should be replaced with feeding the events from certain point in history and ensuring there are no gaps in bulletin board.

async pseudovote.service.data_for_bulletin_feed(token)

If conduct election process is disturbed, this enables to condtinue observers still getting the needed audit information in the end of election. This is mostly for convenience and fallback to ensure continuity of the process in case of milder technical disturbances.

async pseudovote.service.data_for_bulletin(token=None, bulletin_id=None, pseudonym='')

Returns basic data for displaying election for a voter or an auditor in vote collector web page or audit web page. Also formats the choices in HTML if they are predefined.

async pseudovote.service.is_in_voterlist(con, voterhash_type, bulletin_id, pseudonym)

Convenience method to detect if pseudonym is in voterlist.

pseudovote.service.conforms_to_choices(ballot, c)

If creator of elections has selected to refrain from storing invalid ballots, this is used to fuzzy match them to provided voter choices.


Currently only replaces newlines with backslashes for better readability in the context of plain text bulletin board.

async pseudovote.service.process_vote(req)

Makes sense of the submitted vote and returns a receipt. This is heavily based on restrictions defined by creator of the poll. Normally the receipt is returned as JSON, but for explicitly defined noscript clients HTML page with receipt is displayed instead. Most of this playing with restrictions is educational and shouldn't be used in normal small scale elections where people trust each other enough to not opt for exhaustive technical manipulations.

async pseudovote.service.distributor_home(req)

This is a home page for bulletin board, currently enabling to create an election for educational or testing purposes, ideally should be accepting voterlist hashes or similar for elections already defined elsewhere.

async pseudovote.service.audit_bulletin(req)

Opens independent audit feed for an election where auditors will be provided data needed to audit the elections of tally the votes. The data displayed is the same displayed on the main election process dashboard except the e-mail sending process.

async pseudovote.service.sitemap(req)

Dynamically generated sitemap.

async pseudovote.service.robots(req)

Dynamically generated robots.txt.

pseudovote.service.get_json_metadata(req, name, alt_name, title, description, params={}, page='home')

Provide style JSON-LD metadata.

pseudovote.service.metadata_for_home(req, name, alt_name, title, description)

JSON-LD metadata for home.

pseudovote.service.metadata_for_bulletin(req, name, alt_name, title, description, params)

JSON-LD metadata for bulletin boards.

pseudovote.service.metadata_for_audit(req, name, alt_name, title, description, params)

JSON-LD metadata for audit dashboards.

async pseudovote.service.select_locale_by_force(req)

Override negotiated locale with the one in URL.


Detect locale specifiec in URL.

async pseudovote.service.serve_i18n_javacript(req)

Since Javascript i18n is always painful, just cut the Gordian knot with serving scripts as translatable templates.

async pseudovote.service.get_app_stats(req)

Display some general information about system status at /api/stats.

pseudovote.util.read_lines(filename, ignore=False)

Read text file into list, if no file, return empty list.

pseudovote.util.to_list(body, key)

Convert request body to list instead of text with newlines.


Convert datetime into format that Javascript reads with timezone etc.

async pseudovote.util.wait_until(stop)

Sleep until next move is needed.

pseudovote.util.run_at(dt, callback, *args)

Create coroutine starting at certain moment.


If the moment has already passed.

pseudovote.util.create_choice_html(r, index, classname, typename, ordered=False)

Create HTML for displaying choices on vote collecting web page (in conjunction with templates/collect.js).