mirror of
https://github.com/tgorordo/smithy.git
synced 2026-06-05 16:22:15 -07:00
move cli script to reduce core package dependencies
This commit is contained in:
parent
2138a0ea6b
commit
8b39991bcd
11 changed files with 251 additions and 141 deletions
148
README.md
148
README.md
|
|
@ -1,5 +1,147 @@
|
|||
# Smithy
|
||||
*A simple smith set solver for ranked-choice ballots.*
|
||||
*A simple Smith set solver for ranked-choice ballots.*
|
||||
|
||||
The Smith set is the minimal set of election candidates which can beat all others pairwise
|
||||
(by simple majority ranking preference) - if there is a single winner in the set they are
|
||||
guaranteed the standard Condorcet i.e. Majority winner (they beat all others pairwise).
|
||||
|
||||
`smithy` currently identifies the set by brute-force search which is combinatoric complexity
|
||||
in the worst case (TODO: better [algorithm](https://en.wikipedia.org/wiki/Floyd%E2%80%93Warshall_algorithm))
|
||||
but appears approximately $O(n^2)$ on-average in the number of candidates for typical/random ballots,
|
||||
and linear in the number of ballots.
|
||||
|
||||
|
||||
## Usage
|
||||
`smithy` can be used a few different ways: as a CLI command, via a web form upload,
|
||||
or imported as a python package (TODO: a small [GUI](https://doc.qt.io/qtforpython-6/)).
|
||||
|
||||
|
||||
### CLI Command
|
||||
`smithy` provides a [`click`](https://click.palletsprojects.com/en/stable/)
|
||||
CLI command defined in `src/cmd.py` which can be invoked a couple of ways:
|
||||
|
||||
- The [GitHub Releases Page](https://github.com/tgorordo/smithy/releases) provides standalone
|
||||
CLI executables bundled using [PyInstaller](https://pyinstaller.org/en/stable/index.html)
|
||||
for linux and windows on `x86_64` and linux on `aarch64`. Downloading the appropriate
|
||||
executable should give you access to the `smithycmd` CLI command.
|
||||
|
||||
- Alternatively, if you are using `uv` (see [Development](#Development)), you can invoke
|
||||
this in your shell as `uv run src/smithycmd.py [...]`.
|
||||
|
||||
In either case, the command expects the same argument structure:
|
||||
TODO
|
||||
|
||||
While plain output is the default, so that the command can easily be used in a unix-pipe
|
||||
or `stdio` workflows, it can also pretty-print its output for your reading pleasure
|
||||
using [`rich`](https://rich.readthedocs.io/en/stable/introduction.html) if you pass it the
|
||||
`--pretty` (or `-p`) flag.
|
||||
|
||||
|
||||
### UOregon CGI Application
|
||||
[**This** `pages.uoregon.edu` page](https://pages.uoregon.edu/tgorordo/files/smithy/src/cgi/form.html)
|
||||
hosts a [CGI form](https://service.uoregon.edu/TDClient/2030/Portal/KB/ArticleDet?ID=43069)
|
||||
which accepts a `.csv` or `.xls`(`x`) upload of a ballot-box and responds with the resulting
|
||||
Smith set. The application can typically handle ~100s of candidates and ~10ks of votes
|
||||
before running into hosting resource limitations and timing out (pathological cases, involving
|
||||
many or large cycles, or especially a large cyclic tie, may perform worse and are not extensively tested).
|
||||
|
||||
|
||||
### Python Package
|
||||
The `smithy` python package primarily provides the function `smith_set(ballot_box_df)`
|
||||
(defined in `src/smithy/rcv.py`), which returns the smith set given a
|
||||
[polars](https://docs.pola.rs/api/python/stable/reference/index.html)
|
||||
dataframe `ballot_box_df` whose columns are candidates and whose rows are RCV ballots.
|
||||
|
||||
e.g. `smithy` can be imported into a [marimo](https://docs.marimo.io/#highlights) notebook
|
||||
as seen in `test/test_nb.py` - if you're using `uv` you can launch marimo via
|
||||
`uv run marimo --edit` and navigate to that example notebook
|
||||
(`just marimo` is an available shorthand if you are using the `just` taskrunner --
|
||||
see [Development](#Development)). Cloning `smithy` then working in scratch notebooks within the repo
|
||||
(e.g. makeing your own `nbs/` directory)
|
||||
is probably the easiest way to use it if you need to do some of cleanup of the tabular
|
||||
data before invocation - just do your cleanup in a notebook using
|
||||
[polars](https://docs.pola.rs/py-polars/html/reference/) then pass a tidy dataframe to `smith_set(df)`.
|
||||
|
||||
Of course, you can also import into any python script or package for a more involved project
|
||||
as well:
|
||||
- If you're using `uv` adding `smithy` should be as simple as
|
||||
```bash
|
||||
uv add git+https://github.com/tgorordo/smithy.git
|
||||
```
|
||||
- Alternatively, if you're using the more default `pip` you can make it available by
|
||||
```bash
|
||||
git clone https://github.com/tgorordo/smithy.git # or submodule add somewhere appropriate in your project
|
||||
cd smithy
|
||||
pip install .
|
||||
```
|
||||
(if you're new to pip-venvs,
|
||||
[this brief guide might be helpful](https://pages.uoregon.edu/tgorordo/courses/uoph410-510a_Image-Analysis/setup.html)).
|
||||
|
||||
|
||||
## Development
|
||||
Current development tooling is based on the [`uv`](https://docs.astral.sh/uv/) Python package and
|
||||
project manager. A [`justfile`](https://github.com/casey/just) lists some common useful
|
||||
task commands. A simple [`shell.nix`](https://nix.dev/tutorials/first-steps/declarative-shell.html)
|
||||
can be used to load these tools into a local environment, and you might find
|
||||
[`direnv`](https://github.com/direnv/direnv) a convenient pairing to `nix` - but just having a
|
||||
system-provided `uv` available is more than enough to use and develop `smithy`.
|
||||
|
||||
|
||||
|
||||
### Formatting, Checking, Testing and Locking
|
||||
Source can be formatted using [`ruff`](https://docs.astral.sh/ruff/) by running
|
||||
```bash
|
||||
uv run ruff format src test
|
||||
```
|
||||
(or `just format`)
|
||||
which should be done before any `git` commit.
|
||||
|
||||
This is not really taken full advantage of at the moment, but type hints can be checked
|
||||
by running
|
||||
```bash
|
||||
uv run pyright src
|
||||
```
|
||||
(or `just check`).
|
||||
|
||||
A test suite can be run as
|
||||
```bash
|
||||
uv run pytest -vvv --tb=short --log-cli-level=INFO
|
||||
```
|
||||
(or `just test`).
|
||||
|
||||
Dependencies can be locked by running
|
||||
```bash
|
||||
uv lock
|
||||
uv pip compile pyproject.toml -o requirements.txt --group dev
|
||||
```
|
||||
(or `just lock`).
|
||||
|
||||
|
||||
### Bundling, Releases, Deployment and Cleanup
|
||||
Bundling with [PyInstaller](https://pyinstaller.org/en/stable/index.html) can be done by
|
||||
```bash
|
||||
uv run pyinstaller --clean -F src/cmd.py --name smithycmd
|
||||
```
|
||||
which will output an executable `smithycmd` for the CLI in `dist/`, which can be uploaded
|
||||
to the latest [GitHub Releases Page](https://github.com/tgorordo/smithy/releases).
|
||||
|
||||
Deploying the main CGI page at
|
||||
[`pages.uoregon.edu/tgorordo/files/smithy/src/cgi`](https://pages.uoregon.edu/tgorordo/files/smithy/src/cgi)
|
||||
requires shell or SFTP access to [my `pages.uoregon.edu`](https://pages.uoregon.edu/tgorordo),
|
||||
which you won't get unless you're [me](https://github.com/tgorordo).
|
||||
|
||||
If you want to deploy it to your own `pages.uoregon.edu` page, then it should be enough to
|
||||
ensure you have [CGI set up](https://service.uoregon.edu/TDClient/2030/Portal/KB/ArticleDet?ID=43069)
|
||||
then SFTP into `sftp.uoregon.edu` and `put -r smithy` (or git clone when `ssh`ed into
|
||||
`shell.uoregon.edu`) wherever you'd like in your `public_html`, ensure `smithy.cgi` has
|
||||
`chmod 755` permissions,
|
||||
[standalone install `uv` for your user](https://docs.astral.sh/uv/getting-started/installation/)
|
||||
then run `uv sync` from somewhere inside the `smithy` directory. Navigating to the `smithy.cgi`
|
||||
file in `pages.uoregon.edu/YOUR_USER/.../cgi/smithy.cgi` should give you a working form.
|
||||
|
||||
If you're using `just` you can cleanup working files by running `just clean` and can fully
|
||||
wipe your `uv` generated `.venv` with `just wipe` (if you want manual versions of those,
|
||||
check the `justfile` definition). It's probably best to do this before any commit as well,
|
||||
though probably not required if you're careful or have `.gitignore` updated appropriately
|
||||
for any changes you made.
|
||||
|
||||
The Smith set is the minimal set of candidates which can beat all others pairwise - if there is a single winner
|
||||
in the set they are guaranteed the standard Condorcet i.e. Majority winner (they beat all others pairwise).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue