Initial commit
This commit is contained in:
commit
10004a555e
5 changed files with 796 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
testdata/
|
394
aliasparts.csv
Normal file
394
aliasparts.csv
Normal 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
|
|
177
anonymize-entries.py
Normal file
177
anonymize-entries.py
Normal 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
207
poetry.lock
generated
Normal 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
17
pyproject.toml
Normal 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"
|
Loading…
Reference in a new issue