mirror of
https://github.com/tgorordo/smithy.git
synced 2026-06-13 02:42:14 -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
|
|
@ -43,10 +43,10 @@
|
|||
|
||||
<h2>About</h2>
|
||||
<p>This is an upload form for the <a href="https://github.com/tgorordo/smithy">smithy</a> RCV Ballot counter for identifying the Smith set (majority winners) in small elections,
|
||||
mainly to help with UO Physics Grad student elections of various flavors. This form uses the <a href="https://service.uoregon.edu/TDClient/2030/Portal/KB/ArticleDet?ID=43069">UO pages.uoregon.edu CGI Capability</a>,
|
||||
mainly to help with <a href="https://blogs.uoregon.edu/physicsgsg/">UO Physics Grad student elections</a> of various flavors. This form uses the <a href="https://service.uoregon.edu/TDClient/2030/Portal/KB/ArticleDet?ID=43069">UO pages.uoregon.edu CGI Capability</a>,
|
||||
so the implementation of smithy being invoked can be <a href="https://pages.uoregon.edu/tgorordo/files/smithy/"> inspected here</a>
|
||||
and you may also inspect the source of this page to verify that <a href="https://pages.uoregon.edu/tgorordo/files/smithy/src/cgi/smithy.cgi?source">this script<a> is called to invoke it - though
|
||||
you have to trust it to be responding with its own contents faithfully.
|
||||
you have to trust it to <a href="https://en.wikipedia.org/wiki/Quine_(computing)">quine</a> itself faithfully.
|
||||
</p>
|
||||
|
||||
<p> The <a href="https://en.wikipedia.org/wiki/Smith_set">Smith set</a> is the minimal set of candidates which can beat all others pairwise (by majority ranking)
|
||||
|
|
|
|||
|
|
@ -1,4 +0,0 @@
|
|||
from smithy import cli
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
|
|
@ -1,77 +1 @@
|
|||
import click
|
||||
import polars as pl
|
||||
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
from rich.panel import Panel
|
||||
|
||||
from .rcv import smith_set
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("spreadsheet", type=click.Path(exists=True, dir_okay=False))
|
||||
def cli(spreadsheet: str) -> None:
|
||||
"""
|
||||
Compute the Smith set from a ranked-choice ballot spreadsheet.
|
||||
|
||||
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 Condorcet i.e. Majority winner.
|
||||
"""
|
||||
|
||||
console = Console()
|
||||
|
||||
try:
|
||||
# Load spreadsheet
|
||||
if spreadsheet.endswith(".csv"):
|
||||
df = pl.read_csv(spreadsheet)
|
||||
|
||||
elif spreadsheet.endswith((".xlsx", ".xls")):
|
||||
df = pl.read_excel(spreadsheet)
|
||||
|
||||
else:
|
||||
console.print(
|
||||
"[bold red]Unsupported file type.[/bold red]\nUse CSV or Excel."
|
||||
)
|
||||
raise SystemExit(1)
|
||||
|
||||
# Normalize numerical dataframe entries
|
||||
df = df.with_columns(
|
||||
[
|
||||
pl.col(c)
|
||||
.cast(pl.Utf8)
|
||||
.str.strip_chars()
|
||||
.cast(pl.Int64, strict=False)
|
||||
.fill_null(0)
|
||||
for c in df.columns
|
||||
]
|
||||
)
|
||||
|
||||
# Compute Smith set
|
||||
smiths = smith_set(df)
|
||||
|
||||
# Preview table
|
||||
preview = Table(title="Ballot Box")
|
||||
|
||||
for col in df.columns:
|
||||
preview.add_column(col)
|
||||
|
||||
for row in df.head(5).iter_rows():
|
||||
preview.add_row(*map(str, row))
|
||||
|
||||
console.print(preview)
|
||||
|
||||
# Results
|
||||
console.print()
|
||||
|
||||
console.print(
|
||||
Panel.fit(
|
||||
"\n".join(f"• {c}" for c in smiths),
|
||||
title="Resulting Smith Set",
|
||||
border_style="green",
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error:[/bold red] {e}")
|
||||
|
||||
raise SystemExit(1)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
import polars as pl
|
||||
from itertools import combinations
|
||||
|
||||
|
||||
def smith_set(df: pl.DataFrame) -> list:
|
||||
"""
|
||||
Compute the Smith set from a Ranked-Choice ballot.
|
||||
|
|
|
|||
86
src/smithycmd.py
Normal file
86
src/smithycmd.py
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
# /// script
|
||||
# requires-python = ">=3.13"
|
||||
# dependencies = [
|
||||
# "click>=8.4.1",
|
||||
# "rich>=15.0.0",
|
||||
# "polars>=1.40.1"
|
||||
# ]
|
||||
# ///
|
||||
import click
|
||||
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
from rich.panel import Panel
|
||||
|
||||
from smithy import smith_set
|
||||
|
||||
@click.command()
|
||||
@click.argument("spreadsheet", type=click.Path(exists=True, dir_okay=False))
|
||||
def cli(spreadsheet: str) -> None:
|
||||
"""
|
||||
Compute the Smith set from a ranked-choice ballot spreadsheet.
|
||||
|
||||
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 Condorcet i.e. Majority winner.
|
||||
"""
|
||||
|
||||
console = Console()
|
||||
|
||||
try:
|
||||
# Load spreadsheet
|
||||
if spreadsheet.endswith(".csv"):
|
||||
df = pl.read_csv(spreadsheet)
|
||||
|
||||
elif spreadsheet.endswith((".xlsx", ".xls")):
|
||||
df = pl.read_excel(spreadsheet)
|
||||
|
||||
else:
|
||||
console.print(
|
||||
"[bold red]Unsupported file type.[/bold red]\nUse CSV or Excel."
|
||||
)
|
||||
raise SystemExit(1)
|
||||
|
||||
# Normalize numerical dataframe entries
|
||||
df = df.with_columns(
|
||||
[
|
||||
pl.col(c)
|
||||
.cast(pl.Utf8)
|
||||
.str.strip_chars()
|
||||
.cast(pl.Int64, strict=False)
|
||||
.fill_null(0)
|
||||
for c in df.columns
|
||||
]
|
||||
)
|
||||
|
||||
# Compute Smith set
|
||||
smiths = smith_set(df)
|
||||
|
||||
# Preview table
|
||||
preview = Table(title="Ballot Box")
|
||||
|
||||
for col in df.columns:
|
||||
preview.add_column(col)
|
||||
|
||||
for row in df.head(5).iter_rows():
|
||||
preview.add_row(*map(str, row))
|
||||
|
||||
console.print(preview)
|
||||
|
||||
# Results
|
||||
console.print()
|
||||
|
||||
console.print(
|
||||
Panel.fit(
|
||||
"\n".join(f"• {c}" for c in smiths),
|
||||
title="Resulting Smith Set",
|
||||
border_style="green",
|
||||
)
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
console.print(f"[bold red]Error:[/bold red] {e}")
|
||||
|
||||
raise SystemExit(1)
|
||||
|
||||
if __name__ == "__main__":
|
||||
cli()
|
||||
Loading…
Add table
Add a link
Reference in a new issue