adds file handling and login generator

This commit is contained in:
waldek 2021-11-09 09:56:45 +01:00
parent 8dc74e59e8
commit 83e42b682c
5 changed files with 2362 additions and 4 deletions

1896
assets/adjectives.txt Normal file

File diff suppressed because it is too large Load Diff

56
assets/login_generator.py Normal file
View File

@ -0,0 +1,56 @@
import random
import string
def load_file(filename):
"""
We load a file and make a list out of it. Note that the same function is
used for both files (both adjectives and subjects). Functions should be
made as generic as possible.
There IS a problem you can fix, some logins will have spaces in them. Try
to remove them in this function!
"""
words = []
with open(filename, "r") as fp:
lines = fp.readlines()
for line in lines:
words.append(line.strip()) # what does strip() do, what does append() do? remember CTRL+Q!
return words
def generate_username():
"""
We'll generate a random pair of adjectives and subjects from two wordlists.
You NEED to have both files in you python project for this to work! Note
the capitalize method call to make it all prettier...
"""
adjectives = load_file("./adjectives.txt")
subjects = load_file("./subjects.txt")
adjective = random.choice(adjectives)
subject = random.choice(subjects)
username = adjective.capitalize() + subject.capitalize()
return username
def generate_password(length=10, complictated=True):
"""
We generate a password with default settings. You can overide these by
changing the arguments in the function call.
"""
password = ""
if complictated:
chars = string.ascii_letters + string.digits + string.punctuation
else:
chars = string.ascii_letters
for i in range(0, length):
password += random.choice(chars)
return password
if __name__ == "__main__":
# let's do some testing!
username_test = generate_username()
print(username_test)
password_test = generate_password()
print(password_test)

61
assets/pwd_cli.py Normal file
View File

@ -0,0 +1,61 @@
import login_generator
def prompt():
"""
We prompt but you KNOW how this works!
"""
response = ""
while not response.isdigit():
response = input("how many login pairs would you like to create?")
return int(response)
def how_long():
"""
And again... (we could combine both prompts, but how?)
"""
response = ""
while not response.isdigit():
response = input("how long should the password be?")
return int(response)
def complex_or_not():
response = ""
while response.lower() not in ["y", "n"]:
response = input("you want complex passwords? (y/n)")
if response.lower() == "y":
return True
else:
return False
def create_login(length, complicated):
"""
We use our library to generate the username and password. The double return
might look confusing but just look at the for loop in the generate_logins
functions and you'll see how it unpacks...
"""
username = login_generator.generate_username()
password = login_generator.generate_password(length, complicated)
return username, password
def generate_logins(number, length, complicated):
"""
Easy no? But what does the i do? Do we really need it's value?
"""
for i in range(0, number):
username, password = create_login(length, complicated)
print("username {}: {}".format(i, username))
print("password {}: {}".format(i, password))
if __name__ == "__main__":
# Here we go!
number_of_logins = prompt()
complicted = complex_or_not()
length = how_long()
generate_logins(number_of_logins, length, complicted)

239
assets/subjects.txt Normal file
View File

@ -0,0 +1,239 @@
Aardvark
African elephant
Albatross
Alley cat
Alligator
Amphibian
Ant
Anteater
Antelope
Ape
Armadillo
Asian elephant
Baboon
Badger
Bat
Bear
Beaver
Beetle
Billy goat
Bison
Boar
Bobcat
Bovine
Bronco
Buck
Buffalo
Bug
Bull
Bunny
BunnyCalf
Camel
Canary
Canine
Caribou
Cat
Caterpillar
Centipede
Chanticleer
Cheetah
Chick
Chimpanzee
Chinchilla
Chipmunk
Clam
Cockatiel
Colt
Condor
Cougar
Cow
Coyote
Crab
Crane
Creature
Crocodile
Crow
Cub
Cur
Cygnet
Deer
Dingo
Dodo
Doe
Dog
Dolphin
Donkey
Dove
Drake
Duck
Eagle
Egret
Elephant
Elk
Emu
Ewe
Falcon
Fawn
Feline
Ferret
Flamingo
Flee
Flies
Foal
Fowl
Fox
Frog
Gander
Gazelle
Gelding
Gerbil
Gibbon
Giraffe
Goat
Goose
Gopher
Gorilla
Grizzly bear
Guinea pig
Hamster
Hare
Hawk
Hedgehog
Heifer
Hippopotamus
Horse
Hound
Hummingbird
Hyena
Ibis
Iguana
Jackal
Jackrabbit
Jaguar
Javalina
Jellyfish
Jenny
Joey
Kangaroo
Kid
Kitten
Kiwi
Koala
Komodo dragon
Krill
Lamb
Lemming
Lemur
Leopard
Lion
Lioness
Llama
Lobster
Lynx
Macaw
Manatee
Marmoset
Marmot
Mink
Minnow
Mite
Mockingbird
Mole
Mongoose
Mongrel
Monkey
Moose
Mouse
Mule
Mustang
Mutt
Nag
Narwhale
Newt
Ocelot
Octopus
Opossum
Orangutan
Orca
Osprey
Ostrich
Otter
Owl
Ox
Pachyderm
Panda
Panther
Parakeet
Parrot
Peacock
Pelican
Penguin
Pheasant
Pig
Pigeon
Piglet
Platypus
Pony
Pooch
Porcupine
Porpoise
Primate
Puppy
Pussycat
Rabbit
Raccoon
Ram
Rat
Reptiles
Rhinoceros
Robin
Rooster
Salamander
Sea lion
Seagull
Seal
Sheep
Sidewinder
Skunk
Sloth
Snail
Snake
Songbird
Sow
Spider
Squid
Squirrel
Stallion
Steer
Stork
Stork
Swan
Tadpole
Tapir
Terrapin
Thoroughbred
Tiger
Toad
Tortoise
Toucan
Turkey
Uakari
Unicorn
Vixen
Vole
Vulture
Wallaby
Walrus
Warthog
Wasp
Weasel
Whale
Wildebeast
Wolf
Wombat
Woodpecker
Worm
X-ray fish
Yak
Zebra

View File

@ -1509,23 +1509,129 @@ print(digits)
# Handling files
When we `import` a library python will read and execute the file in question.
We can also just *read* a simple text file and *use* the data that's in the file.
There are two ways of reading a file, one more *pythonic* and one more linear.
I'll outline both and you can use whichever seems more logical to you.
## Reading from a file
### In-line way
The builtin function `open` is what's new here.
It takes two arguments, one is the [path](https://en.wikipedia.org/wiki/Path_(computing)) and the other is a *mode*.
The most used modes are **read** or **write**, and this as either **text** or **binary**.
Have a look at the documentation to discover more modes.
```python3
fp = open("./examples/data.txt", "r")
data = fp.readlines()
print("file contains: {}".format(data))
fp.close()
```
### Pythonic way
The *exact* same thing can be done in a more pythonic way as follows.
The beauty of the `with` syntax is that the `close` function call is implied by the indentation.
I personally prefer this way of reading and writing files but you do you!
```python3
file_to_open = "./examples/data.txt"
with open(file_to_open, "r") as fp:
data = fp.readlines()
print("file contains: {}".format(data))
print("{} has {} lines".format(file_to_open, len(data)))
```
## Writing to a file
## csv, JSON and yaml
Writing to a file can also be done in two ways, a pythonic and *less* pythonic way.
As I prefer the pythonic way I'll only showcase that one but you'll be able to easily adapt the code yourself.
The only difference is the **mode** we use to `open` the file.
## pickle
```python3
first_name = input("what's your first name? ")
last_name = input("what's your last name? ")
birthday = input("what's your date of birth? ")
data = [first_name, last_name, birthday]
file_to_open = "./examples/test.tmp"
with open(file_to_open, "w") as fp:
for element in data:
fp.write("{}\n".format(element))
print("done!")
```
There is also a way to write a batch of lines to a file in one go.
This is done as follows.
But, you'll notice there is no **newline** added after each element.
```python3
data = ["wouter", "gordts", "1986"]
file_to_open = "./examples/test.tmp"
with open(file_to_open, "w") as fp:
fp.writelines(data)
```
# Coding challenge - Login generator
TODO write a login generator as a library with a cli as program
BONUS argparse, save to file, read from file
Can you write me a program that creates random, but easy to remember, usernames?
Plus, for each username also a *not-so-easy-to-remember* password?
Maybe with a bit of flexibility?
For example variable password length?
This is an exercise you can take pretty far if you plan it out properly.
I would advise you to write the **generator** functions as a library.
Then import those functions into the program where you implement the user facing logic.
By doing so you can reuse your code for multiple interfaces (CLI, TUI, [argparse](https://docs.python.org/3/howto/argparse.html)).
If you want to you can also **save** your logins to a file!
An example of the output I expect:
```
how many login pairs would you like to create?3
you want complex passwords? (y/n)y
how long should the password be?32
username 0: EarnestCrocodile
password 0: :sdGV&[FDYZZ|RXUpZeo`J&t@*Z>^fEW
username 1: AbstractedDragon
password 1: 32hz5&C@<o\OMa9tnET(lk(3wF%d?$Dy
username 2: MeekStallion
password 2: +;^di8a":AD;_b4^w$Fj'RVkI`CoG,LX
```
<details>
<summary>Spoiler warning</summary>
This spoiler warning is in multiple steps.
If you're unsure how to generate the *random-yet-easy-to-remember* have a look at [this file](./assets/subjects.txt) and [this file](./assets/adjectives.txt).
**Stop here and try it out!**
If you're unsure how to tackle the *library part* of this exercise, have a look at [this file](./assets/login_generator.py).
Don't just copy this code, read it and recreate it yourself!
**Stop here and try it out!**
Once the library is done you can code the *interface*.
For some inspiration for a simple question/response system you can have a look [here](./assets/pwd_cli.py).
</details>
# Dictionaries as data containers
TODO adapt the login generator to output a dict
## csv, JSON and yaml
# Creating our own classes
## Class examples