Initial commit

This commit is contained in:
Ash Garcia 2024-08-10 15:51:17 -07:00
commit 10004a555e
5 changed files with 796 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
testdata/

394
aliasparts.csv Normal file
View file

@ -0,0 +1,394 @@
first,second
Balls,Bear
Fluffy,Flight
Fashionable,Handbag
Vengeful,Direction
Embarrass,Example
Night,Attention
Redundant,Bag
Invention,Invention
Modular,Wolf
Closet,Oyster
Pleasant,Pancake
Study,Sun
Ravioli,Result
Boats,Power
Feeling,Donkey
Watery,Water
Construct,Scarecrow
Penitent,Journey
Ripe,Brick
Basketball,Boys
Petite,Pickle
Delicious,Carriage
Jimmy,Jamaica
Lively,Army
Sulky,Visitor
Tricky,Time
Incompetent,Flight
Telephone,Tub
Necessary,Skirt
Penguin,Printer
Mad,Rear
Gamer,Breath
Teeny-Tiny,Toe
Attempt,Dinosaurs
Sudden,Money
Shoot,Side
Zesty,Horse
Annoying,Caption
Paprika,Bane
Team,Wisdom
Offend,Twists
Evening,Supreme
Inca,Kola
Omega,Society
Ladybug,Zoomies
Offbeat,Grass
Charlie,Vibrate
Cheese,Cannon
Bad,Timing
End,Pancake
Climax,Koalas
Solo,Gopher
Courageous,Curtain
Join,Battle
Disagreeable,Behavior
Use,Floor
False,Opinion
Chunky,Curtain
Somber,Bells
Painful,Lawyer
Round,Sphere
Frightening,Credit
Best,Grandfather
Axiom,Address
False,Oil
Soothing,Saxophone
Ugly,Lobby
Whimsical,Advertisement
Marvelous,Toes
Mysterious,Beast
Sulfur,Sphere
Attempt,Nut
Responsible,Floor
Looping,Jungle
Lethal,Geese
Legal,Legs
Mere,Egg
Stocking,Slave
General,Giraffe
Simon,Switch
Purple,Pancake
Nice,Distribution
Flesh,Toothbrush
Political,Argument
Sweet,Creator
Scatter,Boys
Collect,Glue
Salami,Society
Alcoholic,Goat
Swear,Police
Wear,Banana
Display,Smash
Volcano,Frank
Temple,Hippie
Obtain,Loss
Two,Cats
Nice,Spoon
Marvelous,Competition
Long,Lips
Ostentatious,Ocelot
Religion,Gun
Pedro,Pablo
Operation,Cobweb
Dad,Bambino
Cuba,Colombo
Pot,Island
Jungle,Jazz
Strip,Disappointment
Irritating,Idea
Psychotic,Frog
Fearful,Form
Vast,Error
Accurate,Mine
Fretful,Form
Nice,Name
Fascinated,Father
Consider,Hate
Help,Help
Climax,Outside
Ordinary,Thread
Enormous,Icicle
Dark,Development
Enigma,Emerald
Test,Time
Geese,Goose
Functional,Cemetery
Obscene,Thing
Prefer,Pie
Public,Jellyfish
Grumpy,Ghost
Palma,Yes
Society,Shelter
Tasteful,Turn
Accelerate,Breakfast
Blind,Jail
Scream,Connection
Zodiac,Zipper
Disturbed,Man
Orange,Matrix
Pain,Party
Mere,Monkey
Aggressive,Agreement
Name,Son
Propose,Shoes
Lewd,Cake
Hard-To-Find,Stream
Suspend,Sleep
Magic,Mike
Sound,Wave
Song,Credit
Numberless,Design
Play,Segment
Moldy,Maid
Omega,Oregano
Flimsy,Balls
Become,Bat
Neuron,Magenta
Hum,Balls
Shaggy,Destruction
Big,Soup
Noisy,Machine
Convert,Grandmother
Aspiring,Floor
Legs,Help
Alien,Agenda
Exceed,Crack
Nominate,Nut
Stupendous,Brain
Distant,Tomato
Bad,Bells
Stink,Side
Athletic,Snorlax
Economy,Expert
Dynamic,Design
David,Gilbert
Orange,Matrix
Pain,Party
Mere,Monkey
Aggressive,Agreement
Name,Son
Propose,Shoes
Lewd,Cake
Hard-To-Find,Stream
Suspend,Sleep
Magic,Mike
Sound,Wave
Song,Credit
Numberless,Design
Play,Segment
Moldy,Maid
Omega,Oregano
Flimsy,Balls
Become,Bat
Neuron,Magenta
Hum,Balls
Shaggy,Destruction
Big,Soup
Noisy,Machine
Convert,Grandmother
Aspiring,Floor
Legs,Help
Alien,Agenda
Exceed,Crack
Nominate,Nut
Stupendous,Brain
Distant,Tomato
Bad,Bells
Stink,Side
Athletic,Snorlax
Economy,Expert
Dynamic,Design
David,Gilbert
Teal,Pocket
Troubleshoot,Things
Voice,Offset
Paint,Everywhere
Wakeful,Train
Not,Puppy
Disapprove,Year
Uncle,Worm
Bored,Brother
Panoramic,Visitor
Feeble,Fruit
Fantastic,Shop
Swing,Swung
Angry,Father
Tremendous,Expansion
Try,Wing
Punishment,Achiever
Drayze,Money
Plague,Doctor
Calculator,Enter
Barrel,Replica
Wiggly,Boy
Complex,Crook
Mimosa,Monarch
Graffiti,Soul
Ghost,Flower
Slow,Sonic
Bite,Committee
Papa,Puma
Holistic,Tooth
Dramatic,Man
Grouchy,Grape
Juicy,Jazz
Spiky,Chimp
Expect,Pain
Cheese,Meteor
Two,Swords
Psychedelic,Use
Shiver,Sleet
Foresee,Foot
Sonic,Phantom
Pam,Can
Inadvisable,Machine
Game,Cloth
Smiling,Mother
Finger,Sized
Abhorrent,Aftermath
Pancake,Maiden
Sentient,Jalapeño
Snapple,Sider
Employ,Ray
Agenda,Dandy
Punctual,Pennies
Child,Cannon
Jetstream,Sam
Mana,Vein
Smite,Sword
Diva,Dee
Silly,Savage
Genre,Damage
Concussion,Simulator
Chew,Beef
Certainly,Hi-Tech
Born,Loser
Prefers,Broccoli
Spooked,Broccoli
Devilish,Afterthought
Chaos,Dunk
Phobic,Babies
Hammer,Lunchroom
Demonic,Holds
Expo,Jinx
Empowered,Turtle
Amish,Shinobi
More,Thirteens
Disprove,Woman
Young,Thug
Angry,Crayon
Examine,Harmony
Vivacious,Underwear
Operate,Swing
Continue,Frolicking
Nutritious,Pot
Song,Lot
Love,Lift
Saucy,Style
Read,Rules
Steppable,Horror
Large,Tune
Trans,Rights
Flamenco,Hardstyle
Huge,Jazz
Tech,Alert
Maybe,Eleven
Inform,Death
Shapeshifting,Soul
Splashy,Splash
Dimo,Pandering
Snooping,Canine
Tech,Notations
Two,Words
Turnt,Tables
Micro,Mambo
Forgetful,Form
Emotion,Lotion
Nine,Ten
The,The
Sodium,Carbonate
Colorful,Chase
Weed,Steps
Very,Serious
Improved,Nut
Ooh,Ahh
Fasten,Spoon
Substandard,Senior
Dispose,Cigarette
Ghoughpteighbteau,Tchoghs
Sixty,Nine
Seventeen,Sixteenths
Cool,Ten
Soft,Pants
Stylish,Seagull
Foot,Prints
Bee,Sat
New,Fifteen
Sandwiched,Romance
Makita,Power
No,Fantastics?
Jellyfish,Jambalaya
None,Modifiers
Redacted,Redacted
Butter,Fly
Fray,Yeah
Naur,Non
Go-Go,Ghost
Not,Eleven
Disk,Doctor
Hop,Along
Last,Literature
Corrupt,File
Dazzlin,Darlin
Leaping,Lemons
Boys,Off
Egglord,Turds
Everybody's,Something
Chief,Poser
Get,Funked
Rhythm,Challenge
Easy,Breezy
Diabolic,Dingleberry
Tucan,Bounce
Quatre,Cinq
Vanity,Devil
Alice,Liddell
Friendly,Frog
Secret,Santa
Moonlight,Silver
Imperfect,Title
Chicken,Nugget
Shelf,Elf
Eccentric,Catastrophe
Beaver,Bunions
Dig,Drug
Elegant,Eggnog
Uncharacteristically,Sesquipedalian
Indecisive,Identity
Play,Melty
Tranquil,Rat
Hall,Days
Unexpected,Item
An,Chart
Snail,Spoon
Boss,Fight
Got,Spunned
Throat,Goat
Scientific,Icicle
Grateful,Knot
Sun,Goddess
Banana,Special
Sleigh,It
Impossible,Burst
1 first second
2 Balls Bear
3 Fluffy Flight
4 Fashionable Handbag
5 Vengeful Direction
6 Embarrass Example
7 Night Attention
8 Redundant Bag
9 Invention Invention
10 Modular Wolf
11 Closet Oyster
12 Pleasant Pancake
13 Study Sun
14 Ravioli Result
15 Boats Power
16 Feeling Donkey
17 Watery Water
18 Construct Scarecrow
19 Penitent Journey
20 Ripe Brick
21 Basketball Boys
22 Petite Pickle
23 Delicious Carriage
24 Jimmy Jamaica
25 Lively Army
26 Sulky Visitor
27 Tricky Time
28 Incompetent Flight
29 Telephone Tub
30 Necessary Skirt
31 Penguin Printer
32 Mad Rear
33 Gamer Breath
34 Teeny-Tiny Toe
35 Attempt Dinosaurs
36 Sudden Money
37 Shoot Side
38 Zesty Horse
39 Annoying Caption
40 Paprika Bane
41 Team Wisdom
42 Offend Twists
43 Evening Supreme
44 Inca Kola
45 Omega Society
46 Ladybug Zoomies
47 Offbeat Grass
48 Charlie Vibrate
49 Cheese Cannon
50 Bad Timing
51 End Pancake
52 Climax Koalas
53 Solo Gopher
54 Courageous Curtain
55 Join Battle
56 Disagreeable Behavior
57 Use Floor
58 False Opinion
59 Chunky Curtain
60 Somber Bells
61 Painful Lawyer
62 Round Sphere
63 Frightening Credit
64 Best Grandfather
65 Axiom Address
66 False Oil
67 Soothing Saxophone
68 Ugly Lobby
69 Whimsical Advertisement
70 Marvelous Toes
71 Mysterious Beast
72 Sulfur Sphere
73 Attempt Nut
74 Responsible Floor
75 Looping Jungle
76 Lethal Geese
77 Legal Legs
78 Mere Egg
79 Stocking Slave
80 General Giraffe
81 Simon Switch
82 Purple Pancake
83 Nice Distribution
84 Flesh Toothbrush
85 Political Argument
86 Sweet Creator
87 Scatter Boys
88 Collect Glue
89 Salami Society
90 Alcoholic Goat
91 Swear Police
92 Wear Banana
93 Display Smash
94 Volcano Frank
95 Temple Hippie
96 Obtain Loss
97 Two Cats
98 Nice Spoon
99 Marvelous Competition
100 Long Lips
101 Ostentatious Ocelot
102 Religion Gun
103 Pedro Pablo
104 Operation Cobweb
105 Dad Bambino
106 Cuba Colombo
107 Pot Island
108 Jungle Jazz
109 Strip Disappointment
110 Irritating Idea
111 Psychotic Frog
112 Fearful Form
113 Vast Error
114 Accurate Mine
115 Fretful Form
116 Nice Name
117 Fascinated Father
118 Consider Hate
119 Help Help
120 Climax Outside
121 Ordinary Thread
122 Enormous Icicle
123 Dark Development
124 Enigma Emerald
125 Test Time
126 Geese Goose
127 Functional Cemetery
128 Obscene Thing
129 Prefer Pie
130 Public Jellyfish
131 Grumpy Ghost
132 Palma Yes
133 Society Shelter
134 Tasteful Turn
135 Accelerate Breakfast
136 Blind Jail
137 Scream Connection
138 Zodiac Zipper
139 Disturbed Man
140 Orange Matrix
141 Pain Party
142 Mere Monkey
143 Aggressive Agreement
144 Name Son
145 Propose Shoes
146 Lewd Cake
147 Hard-To-Find Stream
148 Suspend Sleep
149 Magic Mike
150 Sound Wave
151 Song Credit
152 Numberless Design
153 Play Segment
154 Moldy Maid
155 Omega Oregano
156 Flimsy Balls
157 Become Bat
158 Neuron Magenta
159 Hum Balls
160 Shaggy Destruction
161 Big Soup
162 Noisy Machine
163 Convert Grandmother
164 Aspiring Floor
165 Legs Help
166 Alien Agenda
167 Exceed Crack
168 Nominate Nut
169 Stupendous Brain
170 Distant Tomato
171 Bad Bells
172 Stink Side
173 Athletic Snorlax
174 Economy Expert
175 Dynamic Design
176 David Gilbert
177 Orange Matrix
178 Pain Party
179 Mere Monkey
180 Aggressive Agreement
181 Name Son
182 Propose Shoes
183 Lewd Cake
184 Hard-To-Find Stream
185 Suspend Sleep
186 Magic Mike
187 Sound Wave
188 Song Credit
189 Numberless Design
190 Play Segment
191 Moldy Maid
192 Omega Oregano
193 Flimsy Balls
194 Become Bat
195 Neuron Magenta
196 Hum Balls
197 Shaggy Destruction
198 Big Soup
199 Noisy Machine
200 Convert Grandmother
201 Aspiring Floor
202 Legs Help
203 Alien Agenda
204 Exceed Crack
205 Nominate Nut
206 Stupendous Brain
207 Distant Tomato
208 Bad Bells
209 Stink Side
210 Athletic Snorlax
211 Economy Expert
212 Dynamic Design
213 David Gilbert
214 Teal Pocket
215 Troubleshoot Things
216 Voice Offset
217 Paint Everywhere
218 Wakeful Train
219 Not Puppy
220 Disapprove Year
221 Uncle Worm
222 Bored Brother
223 Panoramic Visitor
224 Feeble Fruit
225 Fantastic Shop
226 Swing Swung
227 Angry Father
228 Tremendous Expansion
229 Try Wing
230 Punishment Achiever
231 Drayze Money
232 Plague Doctor
233 Calculator Enter
234 Barrel Replica
235 Wiggly Boy
236 Complex Crook
237 Mimosa Monarch
238 Graffiti Soul
239 Ghost Flower
240 Slow Sonic
241 Bite Committee
242 Papa Puma
243 Holistic Tooth
244 Dramatic Man
245 Grouchy Grape
246 Juicy Jazz
247 Spiky Chimp
248 Expect Pain
249 Cheese Meteor
250 Two Swords
251 Psychedelic Use
252 Shiver Sleet
253 Foresee Foot
254 Sonic Phantom
255 Pam Can
256 Inadvisable Machine
257 Game Cloth
258 Smiling Mother
259 Finger Sized
260 Abhorrent Aftermath
261 Pancake Maiden
262 Sentient Jalapeño
263 Snapple Sider
264 Employ Ray
265 Agenda Dandy
266 Punctual Pennies
267 Child Cannon
268 Jetstream Sam
269 Mana Vein
270 Smite Sword
271 Diva Dee
272 Silly Savage
273 Genre Damage
274 Concussion Simulator
275 Chew Beef
276 Certainly Hi-Tech
277 Born Loser
278 Prefers Broccoli
279 Spooked Broccoli
280 Devilish Afterthought
281 Chaos Dunk
282 Phobic Babies
283 Hammer Lunchroom
284 Demonic Holds
285 Expo Jinx
286 Empowered Turtle
287 Amish Shinobi
288 More Thirteens
289 Disprove Woman
290 Young Thug
291 Angry Crayon
292 Examine Harmony
293 Vivacious Underwear
294 Operate Swing
295 Continue Frolicking
296 Nutritious Pot
297 Song Lot
298 Love Lift
299 Saucy Style
300 Read Rules
301 Steppable Horror
302 Large Tune
303 Trans Rights
304 Flamenco Hardstyle
305 Huge Jazz
306 Tech Alert
307 Maybe Eleven
308 Inform Death
309 Shapeshifting Soul
310 Splashy Splash
311 Dimo Pandering
312 Snooping Canine
313 Tech Notations
314 Two Words
315 Turnt Tables
316 Micro Mambo
317 Forgetful Form
318 Emotion Lotion
319 Nine Ten
320 The The
321 Sodium Carbonate
322 Colorful Chase
323 Weed Steps
324 Very Serious
325 Improved Nut
326 Ooh Ahh
327 Fasten Spoon
328 Substandard Senior
329 Dispose Cigarette
330 Ghoughpteighbteau Tchoghs
331 Sixty Nine
332 Seventeen Sixteenths
333 Cool Ten
334 Soft Pants
335 Stylish Seagull
336 Foot Prints
337 Bee Sat
338 New Fifteen
339 Sandwiched Romance
340 Makita Power
341 No Fantastics?
342 Jellyfish Jambalaya
343 None Modifiers
344 Redacted Redacted
345 Butter Fly
346 Fray Yeah
347 Naur Non
348 Go-Go Ghost
349 Not Eleven
350 Disk Doctor
351 Hop Along
352 Last Literature
353 Corrupt File
354 Dazzlin Darlin
355 Leaping Lemons
356 Boys Off
357 Egglord Turds
358 Everybody's Something
359 Chief Poser
360 Get Funked
361 Rhythm Challenge
362 Easy Breezy
363 Diabolic Dingleberry
364 Tucan Bounce
365 Quatre Cinq
366 Vanity Devil
367 Alice Liddell
368 Friendly Frog
369 Secret Santa
370 Moonlight Silver
371 Imperfect Title
372 Chicken Nugget
373 Shelf Elf
374 Eccentric Catastrophe
375 Beaver Bunions
376 Dig Drug
377 Elegant Eggnog
378 Uncharacteristically Sesquipedalian
379 Indecisive Identity
380 Play Melty
381 Tranquil Rat
382 Hall Days
383 Unexpected Item
384 An Chart
385 Snail Spoon
386 Boss Fight
387 Got Spunned
388 Throat Goat
389 Scientific Icicle
390 Grateful Knot
391 Sun Goddess
392 Banana Special
393 Sleigh It
394 Impossible Burst

177
anonymize-entries.py Normal file
View file

@ -0,0 +1,177 @@
import argparse
import csv
import _csv
import os
from random import Random
import sys
from tempfile import TemporaryDirectory
from typing import Optional
from zipfile import ZipFile
from fs.zipfs import ZipFS
import simfile
####################
# Script arguments #
####################
class AnonymizeEntriesArgs:
"""Stores the command-line arguments for this script."""
csv: str
files: str
dry_run: bool
def argparser():
"""Get an ArgumentParser instance for this command-line script."""
parser = argparse.ArgumentParser()
parser.add_argument("csv", type=str, help="path to the CSV file of form responses")
parser.add_argument(
"files", type=str, help="path to the directory of file responses"
)
parser.add_argument(
"-d",
"--dry-run",
action=argparse.BooleanOptionalAction,
help="preview changes without writing the file",
)
return parser
CsvContents = list[dict[str, str]]
################
# Script logic #
################
def assert_valid_file_paths(args: AnonymizeEntriesArgs):
assert os.path.isfile(args.csv), f"{repr(args.csv)} is not a file"
assert os.path.isdir(args.files), f"{repr(args.files)} is not a directory"
def load_csv_contents(args: AnonymizeEntriesArgs):
with open(args.csv, "r") as csvfile:
return list(csv.DictReader(csvfile))
def load_alias_parts(csvpath: str) -> tuple[list[str], list[str]]:
def extract_alias_parts(csv: "_csv._reader"):
return tuple(zip(*((line[0], line[1]) for n, line in enumerate(csv) if n > 0)))
with open(csvpath, "r") as csvfile:
alias_parts = extract_alias_parts(csv.reader(csvfile))
print(f"Loaded {sum(len(part) for part in alias_parts)} alias parts")
return alias_parts
def assert_known_google_forms_columns_present(csv_contents: CsvContents):
assert (
"Timestamp" in csv_contents[0]
), 'Provided CSV file does not have a "Timestamp" column'
assert (
"Email Address" in csv_contents[0]
), 'Provided CSV file does not have an "Email Address" column'
def detect_filename_column(csv_contents: CsvContents) -> str:
maybe_filename_columns = [
column for (column, value) in csv_contents[0].items() if value.endswith(".zip")
]
assert (
len(maybe_filename_columns) != 0
), 'First data row of provided CSV file has no cell ending in ".zip"'
assert (
len(maybe_filename_columns) == 1
), 'First data row of provided CSV file has multiple cells ending in ".zip"'
filename_column = maybe_filename_columns[0]
print(f"Detected filename column: {repr(filename_column)}")
return filename_column
def maybe_generate_and_persist_aliases(
args: AnonymizeEntriesArgs,
alias_parts: tuple[list[str], list[str]],
csv_contents: CsvContents,
):
reuse_aliases = "Generated Alias" in csv_contents[0]
if reuse_aliases:
print("Reusing generated aliases")
else:
for row in csv_contents:
random = Random("; ".join([row["Email Address"], args.csv, args.files]))
row["Generated Alias"] = (
f"{random.choice(alias_parts[0])} {random.choice(alias_parts[0])}"
)
print("Generated an alias for each entry")
if args.dry_run:
print("Dry run - not writing generated aliases back to CSV")
else:
with open(args.csv, "w", newline="") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=csv_contents[0].keys())
writer.writeheader()
for row in csv_contents:
writer.writerow(row)
print("Wrote generated aliases back to CSV")
return 0
def maybe_remove_and_persist_resubmitted_entries(csv_contents: CsvContents):
print("STUB - maybe_remove_and_persist_resubmitted_entries")
def extract_entries_to_temporary_folder(
args: AnonymizeEntriesArgs, csv_contents: CsvContents
):
print("STUB - extract_entries_to_temporary_folder")
def anonymize_entries(
args: AnonymizeEntriesArgs,
csv_contents: CsvContents,
temp_dir: Optional[TemporaryDirectory],
):
print("STUB - anonymize_entries")
def zip_anonymized_entries(
args: AnonymizeEntriesArgs,
csv_contents: CsvContents,
temp_dir: Optional[TemporaryDirectory],
):
print("STUB - zip_anonymized_entries")
###############
# Main method #
###############
def main(argv: list[str]):
args = argparser().parse_args(argv[1:], namespace=AnonymizeEntriesArgs())
assert_valid_file_paths(args)
alias_parts = load_alias_parts("aliasparts.csv")
csv_contents = load_csv_contents(args)
assert_known_google_forms_columns_present(csv_contents)
filename_column = detect_filename_column(csv_contents)
maybe_generate_and_persist_aliases(args, alias_parts, csv_contents)
# Everything above is implemented; everything below is a stub
maybe_remove_and_persist_resubmitted_entries(csv_contents)
temp_folder = extract_entries_to_temporary_folder(args, csv_contents)
anonymize_entries(args, csv_contents, temp_folder)
zip_anonymized_entries(args, csv_contents, temp_folder)
if __name__ == "__main__":
main(sys.argv)

207
poetry.lock generated Normal file
View file

@ -0,0 +1,207 @@
# This file is automatically @generated by Poetry 1.5.1 and should not be changed by hand.
[[package]]
name = "appdirs"
version = "1.4.4"
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
optional = false
python-versions = "*"
files = [
{file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"},
{file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"},
]
[[package]]
name = "black"
version = "24.8.0"
description = "The uncompromising code formatter."
optional = false
python-versions = ">=3.8"
files = [
{file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"},
{file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"},
{file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"},
{file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"},
{file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"},
{file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"},
{file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"},
{file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"},
{file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"},
{file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"},
{file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"},
{file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"},
{file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"},
{file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"},
{file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"},
{file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"},
{file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"},
{file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"},
{file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"},
{file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"},
{file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"},
{file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"},
]
[package.dependencies]
click = ">=8.0.0"
mypy-extensions = ">=0.4.3"
packaging = ">=22.0"
pathspec = ">=0.9.0"
platformdirs = ">=2"
[package.extras]
colorama = ["colorama (>=0.4.3)"]
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
uvloop = ["uvloop (>=0.15.2)"]
[[package]]
name = "click"
version = "8.1.7"
description = "Composable command line interface toolkit"
optional = false
python-versions = ">=3.7"
files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[package.dependencies]
colorama = {version = "*", markers = "platform_system == \"Windows\""}
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "fs"
version = "2.4.16"
description = "Python's filesystem abstraction layer"
optional = false
python-versions = "*"
files = [
{file = "fs-2.4.16-py2.py3-none-any.whl", hash = "sha256:660064febbccda264ae0b6bace80a8d1be9e089e0a5eb2427b7d517f9a91545c"},
{file = "fs-2.4.16.tar.gz", hash = "sha256:ae97c7d51213f4b70b6a958292530289090de3a7e15841e108fbe144f069d313"},
]
[package.dependencies]
appdirs = ">=1.4.3,<1.5.0"
setuptools = "*"
six = ">=1.10,<2.0"
[package.extras]
scandir = ["scandir (>=1.5,<2.0)"]
[[package]]
name = "msdparser"
version = "2.0.0"
description = "Robust & lightning fast MSD parser (StepMania file format)"
optional = false
python-versions = ">=3.6"
files = [
{file = "msdparser-2.0.0-py3-none-any.whl", hash = "sha256:bbef8c89b2dc16183ba714354b093fff11a43469971c42972284c5046826002d"},
{file = "msdparser-2.0.0.tar.gz", hash = "sha256:9bb6cf4b705c76850b1ce22823c768b62ba2bb63d1c2407bbe3e2c23e38be8e3"},
]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = false
python-versions = ">=3.5"
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
name = "packaging"
version = "24.1"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
]
[[package]]
name = "pathspec"
version = "0.12.1"
description = "Utility library for gitignore style pattern matching of file paths."
optional = false
python-versions = ">=3.8"
files = [
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
]
[[package]]
name = "platformdirs"
version = "4.2.2"
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
optional = false
python-versions = ">=3.8"
files = [
{file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
{file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
]
[package.extras]
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
type = ["mypy (>=1.8)"]
[[package]]
name = "setuptools"
version = "72.1.0"
description = "Easily download, build, install, upgrade, and uninstall Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "setuptools-72.1.0-py3-none-any.whl", hash = "sha256:5a03e1860cf56bb6ef48ce186b0e557fdba433237481a9a625176c2831be15d1"},
{file = "setuptools-72.1.0.tar.gz", hash = "sha256:8d243eff56d095e5817f796ede6ae32941278f542e0f941867cc05ae52b162ec"},
]
[package.extras]
core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.text (>=3.7)", "more-itertools (>=8.8)", "ordered-set (>=3.1.1)", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"]
doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.11.*)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (<0.4)", "pytest-ruff (>=0.2.1)", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
[[package]]
name = "simfile"
version = "2.1.1"
description = "Modern simfile library for Python"
optional = false
python-versions = ">=3.6"
files = [
{file = "simfile-2.1.1-py3-none-any.whl", hash = "sha256:133094a33cf6b841ca7e620880ef8354c56dd4aef6b2c77582de7f120f69c620"},
{file = "simfile-2.1.1.tar.gz", hash = "sha256:a7885f8395cdd0f19cd79da34e5675da778aa0e8dda76543cf075e21b862c4b7"},
]
[package.dependencies]
fs = ">=2.4.15,<2.5.0"
msdparser = ">=2.0.0,<2.1.0"
[[package]]
name = "six"
version = "1.16.0"
description = "Python 2 and 3 compatibility utilities"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
[metadata]
lock-version = "2.0"
python-versions = "^3.11"
content-hash = "130aa8886dcc190a88f8094e7e74aefbddad10ce60ab3d63d74c126bf6b5cc04"

17
pyproject.toml Normal file
View file

@ -0,0 +1,17 @@
[tool.poetry]
name = "dimocracy-voucher"
version = "0.1.0"
description = ""
authors = ["ashastral <git@ashastral.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.11"
simfile = "^2.1.1"
[tool.poetry.group.dev.dependencies]
black = "^24.8.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"