├── .gitignore
├── README.md
├── ajax_notes.md
├── binary_and_unicode.py
├── bokeh_example.py
├── booleans.py
├── builtin_functions.py
├── classes.py
├── composition.py
├── comprehensions.py
├── concurrency.py
├── conditionals.py
├── context_managers.py
├── data
├── NEO_historical.csv
├── accounts1.sqlite
├── accounts2.sqlite
├── backups
│ └── test.txt
├── bohemian_rhapsody_lyrics.txt
├── cities.csv
├── death_valley_2014.csv
├── definitions
├── example.txt
├── filename.txt
├── img
│ ├── bokeh-example.png
│ ├── folium-example.png
│ ├── matplotlib-csv-example.png
│ ├── matplotlib-example.png
│ ├── matplotlib-examples.png
│ ├── pygal-example-1.png
│ ├── pygal-example-2.png
│ ├── pygal-intro.png
│ ├── pygal-json-example.png
│ ├── tkinter-example.png
│ └── tkinter-module.png
├── map1.html
├── menu.json
├── music.pickle
├── music
│ ├── Beatles
│ │ └── Sgt. Pepper's Lonely Hearts Club Band
│ │ │ ├── 1 - Sgt. Pepper's Lonely Hearts Club Band.emp3
│ │ │ ├── 10 - Lovely Rita.emp3
│ │ │ ├── 11 - Good Morning Good Morning.emp3
│ │ │ ├── 12 - Sgt. Pepper's Lonely Hearts Club Band (reprise).emp3
│ │ │ ├── 13 - A Day In The Life.emp3
│ │ │ ├── 2 - With A Little Help From My Friends.emp3
│ │ │ ├── 3 - Lucy In The Sky With Diamonds.emp3
│ │ │ ├── 4 - Getting Better.emp3
│ │ │ ├── 5 - Fixing A Hole.emp3
│ │ │ ├── 6 - She's Leaving Home.emp3
│ │ │ ├── 7 - Being For The Benefit Of Mr. Kite.emp3
│ │ │ ├── 8 - Within You Without You.emp3
│ │ │ └── 9 - When I'm Sixty-Four.emp3
│ ├── Bernie Torme
│ │ └── Demolition Ball
│ │ │ ├── 1 - Fallen Angel.emp3
│ │ │ ├── 10 - Draw The Line.emp3
│ │ │ ├── 11 - U.S. Maid.emp3
│ │ │ ├── 12 - Let It Go.emp3
│ │ │ ├── 13 - Walk It.emp3
│ │ │ ├── 14 - Man O'Means.emp3
│ │ │ ├── 15 - Monkey Business.emp3
│ │ │ ├── 16 - My Darlene.emp3
│ │ │ ├── 2 - Black Sheep.emp3
│ │ │ ├── 3 - Action.emp3
│ │ │ ├── 4 - Ball & Chain.emp3
│ │ │ ├── 5 - Slip Away.emp3
│ │ │ ├── 6 - Long Time Coming.emp3
│ │ │ ├── 7 - Spinnin' Your Wheels.emp3
│ │ │ ├── 8 - Don't Understand.emp3
│ │ │ └── 9 - Industry.emp3
│ └── Beth Orton
│ │ └── Trailer Park
│ │ ├── 1 - She Cries Your Name.emp3
│ │ ├── 10 - I Wish I Never Saw The Sunshine.emp3
│ │ ├── 11 - Galaxy Of Emptiness.emp3
│ │ ├── 2 - Tangent.emp3
│ │ ├── 3 - Don't Need A Reason.emp3
│ │ ├── 4 - Live As You Dream.emp3
│ │ ├── 5 - Sugar Boy.emp3
│ │ ├── 6 - Touch Me With Your Love.emp3
│ │ ├── 7 - Whenever.emp3
│ │ ├── 8 - How Far.emp3
│ │ └── 9 - Someone's Daughter.emp3
├── my_files
│ └── test.txt
├── neo_btc.csv
├── neo_usd.csv
├── numbers.json
├── pizzas
├── plants_shelf
├── population_data.json
├── practice.cfg
├── practice.xml
├── practice.yaml
├── practice1.txt
├── practice2.txt
├── singers.csv
├── supermarkets-commas.txt
├── supermarkets-semicolons.txt
├── supermarkets.csv
├── supermarkets.json
├── supermarkets.xlsx
├── test.log
├── test.txt
├── verlegenhuken.xlsx
├── volcanoes.csv
└── world.json
├── data_types.py
├── data_visualization.md
├── dataclasses_module.py
├── date_time_examples.py
├── date_time_modules.py
├── debugging.py
├── decorators.py
├── demos
├── americas.svg
├── die_visual_1.svg
├── die_visual_2.svg
├── die_visual_3.svg
├── line_plot1.html
├── line_plot2.html
├── redis_dryer.py
├── redis_pub.py
├── redis_sub.py
├── redis_washer.py
├── sample_plot.png
├── scatter_plot1.html
├── scatter_plot2.html
├── tasks.py
├── tasks_with_info.py
├── tcp_client.py
├── tcp_server.py
├── udp_client.py
└── udp_server.py
├── deployment.md
├── deployment_digitalocean.md
├── deployment_docker.md
├── deployment_heroku.md
├── design_patterns.md
├── dictionaries.py
├── documenting_naming.py
├── escape_characters.py
├── exceptions.py
├── files_read_write.py
├── flask_blueprints_and_app_factory.md
├── flask_bootstrap.md
├── flask_jinja_notes.md
├── flask_mqtt.md
├── flask_multiple_databases.md
├── flask_socketio.md
├── flask_user_roles.md
├── folium_webmaps.py
├── formatting.py
├── functions.py
├── generators.py
├── geopy_module.py
├── helper_functions.py
├── import_modules.py
├── inheritance.py
├── iterables_summary.py
├── iterating_with_for.py
├── json_example.py
├── jupyter_notebook.md
├── keywords.py
├── lists.py
├── logging_errors.py
├── magic_methods.py
├── match_statements.py
├── matplotlib_csv_example.py
├── matplotlib_example.py
├── matplotlib_intro.py
├── namespaces.py
├── networks.md
├── noSQL_datastores.py
├── numpy_modules.py
├── operators.py
├── package_management.md
├── packages_example.md
├── pandas_data_analysis.py
├── pickling.py
├── polymorphism.py
├── postgreSQL_example.py
├── postman.md
├── pyenv.md
├── pygal_github_api_example.py
├── pygal_hn_api_example.py
├── pygal_intro.py
├── pygal_json_example.py
├── queues.py
├── recursion.py
├── reflection.py
├── regular_expressions.py
├── relational_databases.py
├── resources.py
├── rest_APIs.md
├── rounding_example.py
├── sets.py
├── shelve_module.py
├── sqlite3_example1.py
├── sqlite3_example2.py
├── standard_library.py
├── strings.py
├── structured_file_formats.py
├── system.py
├── template.py
├── terminology.py
├── testing.py
├── timezones.py
├── timezones_example.py
├── tkinter_example.py
├── tkinter_module.py
├── tuples.py
├── virtual_environments.md
├── web_scraping.py
├── web_servers_frameworks.py
├── while_loops.py
└── zip_function.py
/.gitignore:
--------------------------------------------------------------------------------
1 | # https://git-scm.com/docs/gitignore
2 | # https://help.github.com/articles/ignoring-files/
3 |
4 | # dependencies
5 | /node_modules
6 |
7 | # bytecode compiled
8 | __pycache__/
9 |
10 | # environments
11 | .env
12 | /venv
13 |
14 | # logs
15 | /logs
16 |
17 | # database
18 | app.db
19 | dump.rdb
20 |
21 | # misc
22 | .DS_Store
23 |
24 | # project specific
25 | requirements.txt
26 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # python notes
2 |
3 |
4 | ## description
5 | In my path to learning Python, I'll be collecting my notes and example code here for reference and review purposes. Filenames reflect the topic as much as possible. The data directory contains resources for some of the examples. To date, my training is self-guided through the use of text books and online resources.
6 |
7 | ## credits
8 | Some examples and comments may come from the following:
9 |
10 | - [Introducing Python](http://shop.oreilly.com/product/0636920028659.do) - *Bill Lubanovic*
11 | - [Python Crash Course](https://nostarch.com/pythoncrashcourse) - *Eric Matthes*
12 | - [Python Playground](https://nostarch.com/pythonplayground) - *Mahesh Venkitachalam*
13 | - [The Python 3 Standard Library by Example](https://doughellmann.com/blog/the-python-3-standard-library-by-example/) - *Doug Hellmann*
14 | - [The Flask Mega-Tutorial](https://courses.miguelgrinberg.com/) - *Miguel Grinberg*
15 | - [Flask Web Development](http://shop.oreilly.com/product/0636920089056.do) - *Miguel Grinberg*
16 | - [Python Cookbook](http://shop.oreilly.com/product/0636920027072.do) - *David Beazley & Brian K. Jones*
17 | - [Python: Master the Art of Design Patterns](https://www.oreilly.com/library/view/python-master-the/9781787125186/) - *Phillips, Girighar, Kasampalis*
18 | - [Effective Python](https://effectivepython.com/) - *Brett Slatkin*
19 | - [Complete Python Masterclass](https://www.udemy.com/python-the-complete-python-developer-course/) - *Udemy course*
20 | - [The Python Mega Course: Build 10 Real World Applications](https://www.udemy.com/the-python-mega-course/) - *Udemy course*
21 | - [REST APIs with Flask and Python](https://www.udemy.com/rest-api-flask-and-python/) - *Udemy course*
22 | - [Think Python](https://greenteapress.com/wp/think-python/) - *Allen B. Downey*
23 | - [Learn Python the Hard Way](https://learnpythonthehardway.org/) - *Zed Shaw*
24 | - [Python documentation](https://docs.python.org/3/index.html) - Python Software Foundation
25 |
26 | Very special thanks to [aleph2c](https://github.com/aleph2c) for the unending explanations, knowledge and support. Check out his epic [python statechart library; Miros here](https://aleph2c.github.io/miros/index.html).
27 |
28 | ## images
29 |
30 | From [**bokeh_example.py**](bokeh_example.py)
31 | 
32 |
33 | From [**folium_webmaps.py**](folium_webmaps.py)
34 | 
35 |
36 | From [**matplotlib_intro.py**](matplotlib_intro.py)
37 | 
38 |
39 | From [**matplotlib_example.py**](matplotlib_example.py)
40 | 
41 |
42 | From [**matplotlib_csv_example.py**](matplotlib_csv_example.py)
43 | 
44 |
45 | From [**pygal_intro.py**](pygal_intro.py)
46 | 
47 |
48 | From [**pygal_json_example.py**](pygal_json_example.py)
49 | 
50 |
51 | From [**pygal_api_example1.py**](pygal_api_example1.py)
52 | 
53 |
54 | From [**pygal_api_example2.py**](pygal_api_example2.py)
55 | 
56 |
57 | From [**tkinter_module.py**](tkinter_module.py)
58 |
59 |
60 | From [**tkinter_example.py**](tkinter_example.py)
61 |
62 |
--------------------------------------------------------------------------------
/booleans.py:
--------------------------------------------------------------------------------
1 | '''Booleans: True False Logic'''
2 |
3 |
4 | # Boolean values are the two constant objects False and True. In numeric
5 | # contexts, they behave like the integers 0 and 1, respectively. The built-in
6 | # function bool() can be used to check any value as a Boolean, if the value can
7 | # be interpreted as a truth value.
8 |
9 | a = [1, 3, 6]
10 | b = []
11 | c = None
12 |
13 | print(bool(a)) # True
14 | print(bool(b)) # False
15 | print(bool(c)) # False
16 |
17 | # True
18 | # False
19 | # and
20 | # or
21 | # in
22 | # is
23 | # not
24 | # not ... or
25 | # not ... and
26 | # not in
27 | # is not
28 | # ==
29 | # !=
30 | # >=
31 | # <=
32 |
33 | # Any 'and' expression that has a False is immediately False
34 | # Any 'or' expression that has a True is immediately True
35 |
36 | print(not False) # True
37 | print(not True) # False
38 | print(True or False) # True
39 | print(True or True) # True
40 | print(False or True) # True
41 | print(False or False) # False
42 | print(True and False) # False
43 | print(True and True) # True
44 | print(False and True) # False
45 | print(False and False) # False
46 | print(not (True or False)) # False
47 | print(not (True or True)) # False
48 | print(not (False or True)) # False
49 | print(not (False or False)) # True
50 | print(not (True and False)) # True
51 | print(not (True and True)) # False
52 | print(not (False and True)) # True
53 | print(not (False and False)) # True
54 | print(1 != 0) # True
55 | print(1 != 1) # False
56 | print(0 != 1) # True
57 | print(0 != 0) # False
58 | print(1 == 0) # False
59 | print(1 == 1) # True
60 | print(0 == 1) # False
61 | print(0 == 0) # True
62 |
--------------------------------------------------------------------------------
/composition.py:
--------------------------------------------------------------------------------
1 | '''Composition & Aggregation'''
2 |
3 |
4 | # Inheritance is a good technique (child is-a parent) but it can be tempting
5 | # to build elaborate inheritance hierarchies. Sometimes composition or
6 | # aggregation (x has-a y) makes more sense. There is actually a difference
7 | # between composition and aggregation though they often blur together.
8 |
9 |
10 | # Composition
11 | # -----------------------------------------------------------------------------
12 | # In this example, the Room class creates a Floor object and a Windows object.
13 | # The arguments for these two objects are passed in when the Room is created.
14 | # If the Room is deleted, so are the Floor and Window instances.
15 |
16 | class Floor():
17 | def __init__(self, material):
18 | self.material = material
19 |
20 | class Windows():
21 | def __init__(self, quantity):
22 | self.quantity = quantity
23 |
24 | class Room():
25 | def __init__(self, floor, windows):
26 | self.floor = Floor(floor)
27 | self.windows = Windows(windows)
28 | def about(self):
29 | print('This room has', self.floor.material, 'floors and',
30 | self.windows.quantity, 'windows')
31 |
32 | bathroom = Room('tiled', 0)
33 | bathroom.about() # This room has tiled floors and 0 windows
34 |
35 |
36 | # Aggregation
37 | # -----------------------------------------------------------------------------
38 | # Unlike composition, aggregation uses existing instances of objects to build
39 | # up another object. The composed object does not actually own the objects that
40 | # it's composed of. If it's destroyed, those objects continue to exist.
41 |
42 | # This example creates Floor and a Window objects, then passes them as
43 | # arguments to a Room object. If the Room object is deleted, the other two
44 | # objects remain.
45 |
46 | class Floor():
47 | def __init__(self, material):
48 | self.material = material
49 |
50 | class Windows():
51 | def __init__(self, quantity):
52 | self.quantity = quantity
53 |
54 | class Room():
55 | def __init__(self, floor, windows):
56 | self.floor = floor
57 | self.windows = windows
58 | def about(self):
59 | print('This room has', floor.material, 'floors and',
60 | windows.quantity, 'windows')
61 |
62 | floor = Floor('hardwood')
63 | windows = Windows('4')
64 | kitchen = Room(floor, windows)
65 |
66 | kitchen.about() # This room has hardwood floors and 4 windows
67 |
68 |
69 | # Composition vs Inheritance
70 | # -----------------------------------------------------------------------------
71 | # There's always more than one solution. Consider the following where we want
72 | # to include address information for a class. The first example uses
73 | # composition, the second uses inheritance. Both are viable solutions but
74 | # composition (has a) feels like it makes more sense.
75 |
76 | # Composition (Customer has a Address):
77 |
78 | class Address():
79 | def __init__(self, street, city, province, code):
80 | self.street = street
81 | self.city = city
82 | self.province = province
83 | self.code = code
84 |
85 | class Customer():
86 | def __init__(self, name, email, **kwargs):
87 | self.name = name
88 | self.email = email
89 | self.address = Address(**kwargs)
90 |
91 | a = {'street': '1234 Main St.',
92 | 'city': 'Vancouver',
93 | 'province': 'BC',
94 | 'code': 'V5V1X1'}
95 |
96 | c = Customer('bob', 'bob@email.com', **a)
97 |
98 | print(c.address.city)
99 | # Vancouver
100 |
101 |
102 | # Inheritance (Customer is a AddressHolder):
103 |
104 | class AddressHolder():
105 | def __init__(self, street, city, province, code):
106 | self.street = street
107 | self.city = city
108 | self.province = province
109 | self.code = code
110 |
111 | class Customer(AddressHolder):
112 | def __init__(self, name, email, **kwargs):
113 | self.name = name
114 | self.email = email
115 | super().__init__(**kwargs)
116 |
117 | a = {'street': '1234 Main St.',
118 | 'city': 'Victoria',
119 | 'province': 'BC',
120 | 'code': 'V5V1X1'}
121 |
122 | c = Customer('chuck', 'chuck@email.com', **a)
123 |
124 | print(c.city)
125 | # Victoria
126 |
--------------------------------------------------------------------------------
/conditionals.py:
--------------------------------------------------------------------------------
1 | '''If Statements and Conditional Tests'''
2 |
3 |
4 | # At the heart of every if statement is an expression that can be evaluated as
5 | # True or False and this is called a conditional test (also called a boolean
6 | # expression). If the conditional test evaluates as True, python will execute
7 | # the code following the if statement, otherwise it will be ignored.
8 |
9 | cars = ['ford', 'bmw', 'honda', 'subaru']
10 |
11 | # checking for equality:
12 | for car in cars:
13 | if car == 'bmw':
14 | print(car.upper())
15 | else:
16 | print(car.title())
17 |
18 | # checking for inequality:
19 | for car in cars:
20 | if car != 'bmw':
21 | print(car.title())
22 | else:
23 | print(car.upper())
24 |
25 | # Both produce the same result:
26 | # Ford
27 | # BMW
28 | # Honda
29 | # Subaru
30 |
31 |
32 | # if, elif, else chains
33 | # -----------------------------------------------------------------------------
34 |
35 | age = 42
36 |
37 | if age < 5:
38 | admission = 0
39 | elif age < 19:
40 | admission = 5
41 | elif age >= 65:
42 | admission = 3
43 | else:
44 | admission = 10
45 |
46 | print(admission) # 10
47 |
48 | # Note you are not required to have a final else statement. It may be more
49 | # readable to use another elif. Keep in mind if you do it this way, there is no
50 | # catchall at the end, so the value must meet one of the elif conditions or it
51 | # may raise an exception.
52 |
53 | if age < 5:
54 | admission = 0
55 | elif age < 19:
56 | admission = 5
57 | elif age >= 65:
58 | admission = 3
59 | elif age < 65:
60 | admission = 10
61 |
62 |
63 | # Check for values with in, not in
64 | # -----------------------------------------------------------------------------
65 |
66 | users = ['rick', 'morty', 'raja', 'bob']
67 | user = 'morty'
68 |
69 | if user in users:
70 | print('Hello', user.title())
71 | else:
72 | print('Create account')
73 |
74 | # same as:
75 | if user not in users:
76 | print('Create account')
77 | else:
78 | print('Hello', user.title())
79 |
80 |
81 | # Check for multiple conditions
82 | # -----------------------------------------------------------------------------
83 |
84 | import time
85 |
86 | now = time.localtime() #
87 | day = time.strftime('%A', now) #
88 | hour = int(time.strftime('%H', now)) #
89 |
90 | if (4 > hour or hour > 20) and (day != 'Friday') and (day != 'Saturday'):
91 | print('Time for bed!')
92 | else:
93 | print('Carry on.')
94 |
95 |
96 | # if, else assignments
97 | # -----------------------------------------------------------------------------
98 |
99 | flag = True
100 |
101 | x = 100 if flag else 0
102 |
103 | print(f'{flag=}, {x=}')
104 | # flag=True, x=100
105 |
--------------------------------------------------------------------------------
/context_managers.py:
--------------------------------------------------------------------------------
1 | '''Context managers: with expression as variable'''
2 |
3 |
4 | # Context managers allow the execution of initialization and finalization
5 | # code around another block of code. In simpler terms, its helpful for when you
6 | # have two related operations you'd like to execute as a pair, with a block of
7 | # code in between.
8 |
9 | print('set things up') # initialization code
10 | try:
11 | print('do something') # another block of code
12 | finally:
13 | print('tear things down') # finalization code
14 |
15 | # Here, "set things up" could be opening a file, or acquiring some external
16 | # resource, and "tear things down" would then be closing the file, or releasing
17 | # or removing the resource. The try-finally construct guarantees that the
18 | # "tear things down" part is always executed, even if the code that does the
19 | # work doesn’t finish. Perhaps the most common (and important) use of context
20 | # managers is to properly manage resources. The act of opening a file consumes
21 | # a resource (called a file descriptor), and this resource is limited by your
22 | # OS – there are a maximum number of files a process can have open at one time.
23 | # Using a context manager ensures these resources are released.
24 |
25 | with open('data/filename.txt', 'w') as fileobject:
26 | print('do something')
27 |
28 | # So the general translation is that there is a try and finally block running
29 | # behind the scenes. The example below demonstrates this method in another way.
30 | # It says try: __enter__() the block and when completed, finally: __exit__().
31 |
32 | class controlled_execution:
33 | def __enter__(self):
34 | thing = 'set things up'
35 | print(thing)
36 | return thing
37 | def __exit__(self, type, value, traceback):
38 | print('tear things down')
39 |
40 | with controlled_execution() as thing:
41 | print('do something')
42 |
43 | # This is considered a context manager. A context manager is an object that
44 | # defines the runtime context to be established when executing a with statement.
45 | # The context manager handles the entry into, and the exit from, the desired
46 | # runtime context for the execution of the block of code. Context managers are
47 | # normally invoked using the with statement. Typical uses of context managers
48 | # include saving and restoring various kinds of global state, locking and
49 | # unlocking resources, closing opened files, etc.
50 |
51 | # As above, you can implement a context manager as a class. At the very least
52 | # a context manager has __enter__ and __exit__ methods defined.
53 |
54 | # Note the 3 arguments in __exit__(). In a normal situation, these are all
55 | # given a value of None. However, if an exception occurs inside the with block,
56 | # they will be set to values related to the type, value, and traceback for the
57 | # exception. This allows the __exit__ method to do any cleanup code that may
58 | # be required, even if an exception occurred.
59 |
60 | # Here's another example of a context manager that will take a sequence
61 | # of random ascii characters and convert it to string.
62 |
63 | import random
64 | import string
65 |
66 | class StringJoiner(list):
67 | def __enter__(self):
68 | return self
69 | def __exit__(self, type, value, traceback):
70 | self.result = ''.join(self)
71 |
72 | with StringJoiner() as j:
73 | for i in range(15):
74 | j.append(random.choice(string.ascii_letters + string.digits))
75 |
76 | print(j)
77 | # ['T', 'h', '9', 'M', 'F', 'v', 'y', 'Q', 'A', 'b', '6', 'n', 'r', 'x', 'i']
78 |
79 | print(j.result)
80 | # Th9MFvyQAb6nrxi
81 |
82 | # Here's an example of a file opening context manager:
83 |
84 | class File():
85 | def __init__(self, filename, method):
86 | self.file_obj = open(filename, method)
87 |
88 | def __enter__(self):
89 | return self.file_obj
90 |
91 | def __exit__(self, type, value, traceback):
92 | self.file_obj.close()
93 | return True # if you want exceptions to be ignored
94 | return False # if you want to pass the exception up the line
95 |
96 | # By defining __enter__() and __exit__() methods we can use this object
97 | # in a with statement:
98 |
99 | with File('data/test.txt', 'w') as opened_file:
100 | opened_file.write('Hola!')
101 |
102 |
103 | # @contextmanager - example 1
104 | # -----------------------------------------------------------------------------
105 | # You can also construct your own context managers using the contextmanager
106 | # decorator from contextlib. In this case it's the 'yield' keyword that
107 | # separates the enter and exit instructions.
108 |
109 | from contextlib import contextmanager
110 |
111 | @contextmanager
112 | def html_element(name):
113 | print("<{}>".format(name), end='')
114 | yield
115 | print("{}>".format(name))
116 |
117 | with html_element("h1"):
118 | print("Heading", end='') # Heading
119 |
120 |
121 | # @contextmanager - example 2
122 | # -----------------------------------------------------------------------------
123 | # This could be used when you have to change the current directory temporarily
124 | # and then return to where you were:
125 |
126 | from contextlib import contextmanager
127 | import os
128 |
129 | @contextmanager
130 | def working_directory(path):
131 | current_dir = os.getcwd()
132 | os.chdir(path)
133 | try:
134 | yield
135 | finally:
136 | os.chdir(current_dir)
137 |
138 | with working_directory("data") as wd:
139 | pass # do something within data
140 |
141 | # Then you'll be back again in the original working directory
142 |
143 |
144 | # @contextmanager - example 3
145 | # -----------------------------------------------------------------------------
146 | # This example creates a temporary folder and cleans it up when leaving
147 | # the context:
148 |
149 | from contextlib import contextmanager
150 | from tempfile import mkdtemp
151 | import shutil
152 | import time
153 |
154 | @contextmanager
155 | def temporary_dir(*args, **kwargs):
156 | name = mkdtemp(*args, **kwargs)
157 | try:
158 | yield name
159 | finally:
160 | shutil.rmtree(name)
161 |
162 | with temporary_dir() as dirname:
163 | time.sleep(10)
164 | pass # do whatever
165 |
--------------------------------------------------------------------------------
/data/NEO_historical.csv:
--------------------------------------------------------------------------------
1 | ,close,high,low,open,time
2 | 0,35.03,36.67,34.35,35.82,1512172800
3 | 1,36.61,39.6,34.84,35.13,1512259200
4 | 2,41.84,43.19,36.55,36.59,1512345600
5 | 3,38.43,42.82,38.25,41.86,1512432000
6 | 4,34.79,38.73,33.92,38.42,1512518400
7 | 5,34.02,36.87,31.75,34.78,1512604800
8 | 6,35.24,36.48,31.73,34.03,1512691200
9 | 7,35.12,38.11,33.82,35.23,1512777600
10 | 8,32.78,35.17,31.56,35.12,1512864000
11 | 9,35.6,36.2,32.76,32.76,1512950400
12 | 10,37.05,37.6,35.06,35.6,1513036800
13 |
--------------------------------------------------------------------------------
/data/accounts1.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/accounts1.sqlite
--------------------------------------------------------------------------------
/data/accounts2.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/accounts2.sqlite
--------------------------------------------------------------------------------
/data/backups/test.txt:
--------------------------------------------------------------------------------
1 | File created.
2 |
--------------------------------------------------------------------------------
/data/bohemian_rhapsody_lyrics.txt:
--------------------------------------------------------------------------------
1 | Bohemian Rhapsody
2 | Queen
3 |
4 | Is this the real life?
5 | Is this just fantasy?
6 | Caught in a landslide
7 | No escape from reality
8 | Open your eyes
9 | Look up to the skies and see
10 | I'm just a poor boy, I need no sympathy
11 | Because I'm easy come, easy go
12 | A little high, little low
13 | Anyway the wind blows, doesn't really matter to me, to me
14 | Mama, just killed a man
15 | Put a gun against his head
16 | Pulled my trigger, now he's dead
17 | Mama, life had just begun
18 | But now I've gone and thrown it all away
19 | Mama, ooo
20 | Didn't mean to make you cry
21 | If I'm not back again this time tomorrow
22 | Carry on, carry on, as if nothing really matters
23 | Too late, my time has come
24 | Sends shivers down my spine
25 | Body's aching all the time
26 | Goodbye everybody I've got to go
27 | Gotta leave you all behind and face the truth
28 | Mama, ooo (anyway the wind blows)
29 | I don't want to die
30 | I sometimes wish I'd never been born at all
31 | I see a little silhouetto of a man
32 | Scaramouch, scaramouch will you do the fandango
33 | Thunderbolt and lightning very very frightening me
34 | Gallileo, Gallileo,
35 | Gallileo, Gallileo,
36 | Gallileo Figaro - magnifico
37 | But I'm just a poor boy and nobody loves me
38 | He's just a poor boy from a poor family
39 | Spare him his life from this monstrosity
40 | Easy come easy go will you let me go
41 | Bismillah! No we will not let you go - let him go
42 | Bismillah! We will not let you go - let him go
43 | Bismillah! We will not let you go let me go
44 | Will not let you go let me go (never)
45 | Never let you go let me go
46 | Never let me go ooo
47 | No, no, no, no, no, no, no
48 | Oh mama mia, mama mia, mama mia let me go
49 | Beelzebub has a devil put aside for me
50 | For me
51 | For me
52 | So you think you can stone me and spit in my eye
53 | So you think you can love me and leave me to die
54 | Oh baby, can't do this to me baby
55 | Just gotta get out just gotta get right outta here
56 | Ooh yeah, ooh yeah
57 | Nothing really matters
58 | Anyone can see
59 | Nothing really matters nothing really matters to me
60 | Anyway the wind blows
61 |
--------------------------------------------------------------------------------
/data/cities.csv:
--------------------------------------------------------------------------------
1 | France, Paris
2 | venuzuela,caracas
3 | LithuniA,vilnius
4 | argentina,buenos aires
5 | bolivia,la paz
6 | brazil,brasilia
7 | chile,santiago
8 | colombia,Bogotá
9 | ecuador,quito
10 | falkland islands,stanley
11 | french guiana,cayenne
12 | guyana,georgetown
13 | paraguay,Asunción
14 | peru,lima
15 | suriname,paramaribo
16 | uruguay,montevideo
17 | venezuela,caracas
18 | quit
19 |
--------------------------------------------------------------------------------
/data/definitions:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/definitions
--------------------------------------------------------------------------------
/data/example.txt:
--------------------------------------------------------------------------------
1 | This is
2 | filler text
3 | for a demo of list and generator comprehensions
4 | see comprehensions.py
5 | -----
6 |
--------------------------------------------------------------------------------
/data/filename.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/filename.txt
--------------------------------------------------------------------------------
/data/img/bokeh-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/bokeh-example.png
--------------------------------------------------------------------------------
/data/img/folium-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/folium-example.png
--------------------------------------------------------------------------------
/data/img/matplotlib-csv-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/matplotlib-csv-example.png
--------------------------------------------------------------------------------
/data/img/matplotlib-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/matplotlib-example.png
--------------------------------------------------------------------------------
/data/img/matplotlib-examples.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/matplotlib-examples.png
--------------------------------------------------------------------------------
/data/img/pygal-example-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/pygal-example-1.png
--------------------------------------------------------------------------------
/data/img/pygal-example-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/pygal-example-2.png
--------------------------------------------------------------------------------
/data/img/pygal-intro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/pygal-intro.png
--------------------------------------------------------------------------------
/data/img/pygal-json-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/pygal-json-example.png
--------------------------------------------------------------------------------
/data/img/tkinter-example.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/tkinter-example.png
--------------------------------------------------------------------------------
/data/img/tkinter-module.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/img/tkinter-module.png
--------------------------------------------------------------------------------
/data/menu.json:
--------------------------------------------------------------------------------
1 | {"breakfast": {"hours": "7-11", "items": {"breakfast burritos": "$6.00", "pancakes": "$4.00", "bagel": "$2.50"}}, "lunch": {"hours": "11-3", "items": {"sandwich": "$8.00"}}, "dinner": {"hours": "3-10", "items": {"spaghetti": "$9.00"}}}
--------------------------------------------------------------------------------
/data/music.pickle:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/music.pickle
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/1 - Sgt. Pepper's Lonely Hearts Club Band.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/1 - Sgt. Pepper's Lonely Hearts Club Band.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/10 - Lovely Rita.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/10 - Lovely Rita.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/11 - Good Morning Good Morning.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/11 - Good Morning Good Morning.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/12 - Sgt. Pepper's Lonely Hearts Club Band (reprise).emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/12 - Sgt. Pepper's Lonely Hearts Club Band (reprise).
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/13 - A Day In The Life.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/13 - A Day In The Life.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/2 - With A Little Help From My Friends.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/2 - With A Little Help From My Friends.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/3 - Lucy In The Sky With Diamonds.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/3 - Lucy In The Sky With Diamonds.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/4 - Getting Better.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/4 - Getting Better.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/5 - Fixing A Hole.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/5 - Fixing A Hole.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/6 - She's Leaving Home.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/6 - She's Leaving Home.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/7 - Being For The Benefit Of Mr. Kite.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/7 - Being For The Benefit Of Mr. Kite.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/8 - Within You Without You.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/8 - Within You Without You.
--------------------------------------------------------------------------------
/data/music/Beatles/Sgt. Pepper's Lonely Hearts Club Band/9 - When I'm Sixty-Four.emp3:
--------------------------------------------------------------------------------
1 | Beatles/Sgt. Pepper's Lonely Hearts Club Band/9 - When I'm Sixty-Four.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/1 - Fallen Angel.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/1 - Fallen Angel.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/10 - Draw The Line.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/10 - Draw The Line.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/11 - U.S. Maid.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/11 - U.S. Maid.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/12 - Let It Go.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/12 - Let It Go.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/13 - Walk It.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/13 - Walk It.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/14 - Man O'Means.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/14 - Man O'Means.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/15 - Monkey Business.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/15 - Monkey Business.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/16 - My Darlene.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/16 - My Darlene.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/2 - Black Sheep.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/2 - Black Sheep.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/3 - Action.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/3 - Action.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/4 - Ball & Chain.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/4 - Ball & Chain.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/5 - Slip Away.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/5 - Slip Away.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/6 - Long Time Coming.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/6 - Long Time Coming.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/7 - Spinnin' Your Wheels.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/7 - Spinnin' Your Wheels.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/8 - Don't Understand.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/8 - Don't Understand.
--------------------------------------------------------------------------------
/data/music/Bernie Torme/Demolition Ball/9 - Industry.emp3:
--------------------------------------------------------------------------------
1 | Bernie Torme/Demolition Ball/9 - Industry.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/1 - She Cries Your Name.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/1 - She Cries Your Name.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/10 - I Wish I Never Saw The Sunshine.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/10 - I Wish I Never Saw The Sunshine.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/11 - Galaxy Of Emptiness.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/11 - Galaxy Of Emptiness.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/2 - Tangent.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/2 - Tangent.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/3 - Don't Need A Reason.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/3 - Don't Need A Reason.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/4 - Live As You Dream.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/4 - Live As You Dream.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/5 - Sugar Boy.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/5 - Sugar Boy.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/6 - Touch Me With Your Love.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/6 - Touch Me With Your Love.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/7 - Whenever.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/7 - Whenever.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/8 - How Far.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/8 - How Far.
--------------------------------------------------------------------------------
/data/music/Beth Orton/Trailer Park/9 - Someone's Daughter.emp3:
--------------------------------------------------------------------------------
1 | Beth Orton/Trailer Park/9 - Someone's Daughter.
--------------------------------------------------------------------------------
/data/my_files/test.txt:
--------------------------------------------------------------------------------
1 | File created.
2 |
--------------------------------------------------------------------------------
/data/numbers.json:
--------------------------------------------------------------------------------
1 | [[4, 5, 7, 9, 11, 13], "j"]
--------------------------------------------------------------------------------
/data/pizzas:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/pizzas
--------------------------------------------------------------------------------
/data/plants_shelf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/plants_shelf
--------------------------------------------------------------------------------
/data/practice.cfg:
--------------------------------------------------------------------------------
1 | [english]
2 | greeting = Hello
3 | [french]
4 | greeting = Bonjour
5 | [files]
6 | home = /usr/local
7 | # simple interpolation:
8 | bin = %(home)s/bin
9 |
--------------------------------------------------------------------------------
/data/practice.xml:
--------------------------------------------------------------------------------
1 |
2 |
14 |
--------------------------------------------------------------------------------
/data/practice.yaml:
--------------------------------------------------------------------------------
1 | name:
2 | first: James
3 | last: McIntyre
4 | dates:
5 | birth: 1828-05-25
6 | death: 1906-03-31
7 | details:
8 | bearded: true
9 | themes: [cheese, Canada]
10 | books:
11 | url: http://www.gutenberg.org/files/36068/36068-h/36068-h.htm
12 | poems:
13 | - title: 'Motto'
14 | text: |
15 | Politeness, perseverance and pluck,
16 | To their possessor will bring good luck.
17 | - title: 'Canadian Charms'
18 | text: |
19 | Here industry is not in vain,
20 | For we have bounteous crops of grain,
21 | And you behold on every field
22 | Of grass and roots abundant yield,
23 | But after all the greatest charm
24 | Is the snug home upon the farm,
25 | And stone walls now keep cattle warm.
26 |
--------------------------------------------------------------------------------
/data/practice1.txt:
--------------------------------------------------------------------------------
1 | File created.
2 |
--------------------------------------------------------------------------------
/data/practice2.txt:
--------------------------------------------------------------------------------
1 | File created.
2 |
--------------------------------------------------------------------------------
/data/singers.csv:
--------------------------------------------------------------------------------
1 | first,last
2 | Jack,White
3 | Eddie,Vedder
4 | David,Bowie
5 | Josh,Homme
6 | Annie,Lennox
7 |
--------------------------------------------------------------------------------
/data/supermarkets-commas.txt:
--------------------------------------------------------------------------------
1 | ID,Address,City,State,Country,Name,Employees
2 | 1,3666 21st St,San Francisco,CA 94114,USA, Madeira,8
3 | 2,735 Dolores St,San Francisco,CA 94119,USA,Bready Shop,15
4 | 3,332 Hill St,San Francisco,California 94114,USA,Super River,25
5 | 4,3995 23rd St,San Francisco,CA 94114,USA,Ben's Shop,10
6 | 5,1056 Sanchez St,San Francisco,California,USA,Sanchez,12
7 | 6,551 Alvarado St,San Francisco,CA 94114,USA,Richvalley,20
8 |
--------------------------------------------------------------------------------
/data/supermarkets-semicolons.txt:
--------------------------------------------------------------------------------
1 | ID;Address;City;State;Country;Name;Employees
2 | 1;3666 21st St;San Francisco;CA 94114;USA;Madeira;8
3 | 2;735 Dolores St;San Francisco;CA 94119;USA;Bready Shop;15
4 | 3;332 Hill St;San Francisco;California 94114;USA; Super River;25
5 | 4;3995 23rd St;San Francisco;CA 94114;USA;Ben's Shop;10
6 | 5;1056 Sanchez St;San Francisco;California;USA;Sanchez;12
7 | 6;551 Alvarado St;San Francisco;CA 94114;USA;Richvalley;20
8 |
--------------------------------------------------------------------------------
/data/supermarkets.csv:
--------------------------------------------------------------------------------
1 | ID,Address,City,State,Country,Name,Employees
2 | 1,3666 21st St,San Francisco,CA 94114,USA,Madeira,8
3 | 2,735 Dolores St,San Francisco,CA 94119,USA,Bready Shop,15
4 | 3,332 Hill St,San Francisco,California 94114,USA,Super River,25
5 | 4,3995 23rd St,San Francisco,CA 94114,USA,Ben's Shop,10
6 | 5,1056 Sanchez St,San Francisco,California,USA,Sanchez,12
7 | 6,551 Alvarado St,San Francisco,CA 94114,USA,Richvalley,20
8 |
--------------------------------------------------------------------------------
/data/supermarkets.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "ID": 1,
4 | "Address": "3666 21st St",
5 | "City": "San Francisco",
6 | "State": "CA 94114",
7 | "Country": "USA",
8 | "Name": "Madeira",
9 | "Employees": 8
10 | },
11 | {
12 | "ID": 2,
13 | "Address": "735 Dolores St",
14 | "City": "San Francisco",
15 | "State": "CA 94119",
16 | "Country": "USA",
17 | "Name": "Bready Shop",
18 | "Employees": 15
19 | },
20 | {
21 | "ID": 3,
22 | "Address": "332 Hill St",
23 | "City": "San Francisco",
24 | "State": "California 94114",
25 | "Country": "USA",
26 | "Name": "Super River",
27 | "Employees": 25
28 | },
29 | {
30 | "ID": 4,
31 | "Address": "3995 23rd St",
32 | "City": "San Francisco",
33 | "State": "CA 94114",
34 | "Country": "USA",
35 | "Name": "Ben's Shop",
36 | "Employees": 10
37 | },
38 | {
39 | "ID": 5,
40 | "Address": "1056 Sanchez St",
41 | "City": "San Francisco",
42 | "State": "California",
43 | "Country": "USA",
44 | "Name": "Sanchez",
45 | "Employees": 12
46 | },
47 | {
48 | "ID": 6,
49 | "Address": "551 Alvarado St",
50 | "City": "San Francisco",
51 | "State": "CA 94114",
52 | "Country": "USA",
53 | "Name": "Richvalley",
54 | "Employees": 20
55 | }
56 | ]
--------------------------------------------------------------------------------
/data/supermarkets.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/supermarkets.xlsx
--------------------------------------------------------------------------------
/data/test.log:
--------------------------------------------------------------------------------
1 | 2019-07-16 12:05:51,303 DEBUG 23 debug message
2 | 2019-07-16 12:05:51,303 INFO 24 info message
3 | 2019-07-16 12:05:51,304 WARNING 25 warning message
4 | 2019-07-16 12:05:51,304 ERROR 26 error message
5 | 2019-07-16 12:05:51,304 CRITICAL 27 critical message
6 | 2019-07-16 12:05:51,304 DEBUG 48 here is my debug message
7 | 2019-07-16 12:38:03,511 DEBUG 23 debug message
8 | 2019-07-16 12:38:03,511 INFO 24 info message
9 | 2019-07-16 12:38:03,511 WARNING 25 warning message
10 | 2019-07-16 12:38:03,512 ERROR 26 error message
11 | 2019-07-16 12:38:03,512 CRITICAL 27 critical message
12 | 2019-07-16 12:38:03,512 DEBUG 48 here is my debug message
13 | 2019-07-16 12:45:12,277 DEBUG 23 debug message
14 | 2019-07-16 12:45:12,277 INFO 24 info message
15 | 2019-07-16 12:45:12,277 WARNING 25 warning message
16 | 2019-07-16 12:45:12,277 ERROR 26 error message
17 | 2019-07-16 12:45:12,277 CRITICAL 27 critical message
18 | 2019-07-16 12:45:12,278 DEBUG 48 here is my debug message
19 | 2019-07-16 12:45:12,278 SPECIAL_INFO 83 Hey, this is special
20 |
--------------------------------------------------------------------------------
/data/test.txt:
--------------------------------------------------------------------------------
1 | Hola!
--------------------------------------------------------------------------------
/data/verlegenhuken.xlsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/data/verlegenhuken.xlsx
--------------------------------------------------------------------------------
/data_types.py:
--------------------------------------------------------------------------------
1 | '''Functions related to data types & structures'''
2 |
3 |
4 | bool(1) # -> True
5 | float(True) # -> 1.0
6 | int(True) # -> 1
7 | str(True) # -> True
8 | list((1,2,3)) # -> [1, 2, 3]
9 | dict((('a', 'A'), ('b', 'B'), ('c', 'C'))) # -> {'c':'C', 'a':'A', 'b':'B'}
10 | set(['a', 'b', 'c']) # -> {'b', 'c', 'a'}
11 | frozenset(['a', 'b', 'c']) # -> {'c', 'b', 'a'}
12 | tuple(['a', 'b', 'c']) # -> ('a', 'b', 'c')
13 |
14 |
--------------------------------------------------------------------------------
/data_visualization.md:
--------------------------------------------------------------------------------
1 | # Python Data Visualization
2 |
3 | ## Table of Contents
4 |
5 |
6 |
7 | - [pandas](#pandas)
8 | - [Matplotlib](#matplotlib)
9 | - [Pygal](#pygal)
10 | - [Bokeh](#bokeh)
11 | - [Folium](#folium)
12 | - [Plotly](#plotly)
13 | - [ggplot](#ggplot)
14 | - [VisPy](#vispy)
15 | - [Altair](#altair)
16 | - [Data Sources](#data-sources)
17 |
18 |
19 |
20 | ## pandas
21 |
22 | > [pandas](https://pandas.pydata.org/) is a fast, powerful, flexible and easy to use open source data analysis and manipulation tool, built on top of the Python programming language.
23 |
24 | See [pandas_data_analysis.py](pandas_data_analysis.py)
25 |
26 |
27 | ## Matplotlib
28 |
29 | > [Matplotlib](https://matplotlib.org/) is a comprehensive library for creating static, animated, and interactive visualizations in Python.
30 |
31 | See [matplotlib_intro.py](matplotlib_intro.py)
32 | See [matplotlib_example.py](matplotlib_example.py)
33 | See [matplotlib_csv_example.py](matplotlib_csv_example.py)
34 |
35 |
36 | ## Pygal
37 |
38 | [Pygal](http://www.pygal.org/en/stable/) creates interactive SVG charts using python.
39 |
40 | See [pygal_intro.py](pygal_intro.py)
41 | See [pygal_json_example.py](pygal_json_example.py)
42 | See [pygal_github_api_example.py]([pygal_github_api_example.py])
43 | See [pygal_hn_api_example.py](pygal_hn_api_example.py)
44 |
45 |
46 | ## Bokeh
47 |
48 | > [Bokeh](https://docs.bokeh.org/en/latest/index.html) is an interactive visualization library for modern web browsers. It provides elegant, concise construction of versatile graphics, and affords high-performance interactivity over large or streaming datasets. Bokeh can help anyone who would like to quickly and easily make interactive plots, dashboards, and data applications.
49 |
50 | See [bokeh_example.py](bokeh_example.py)
51 |
52 |
53 | ## Folium
54 |
55 | > [folium](https://python-visualization.github.io/folium/) builds on the data wrangling strengths of the Python ecosystem and the mapping strengths of the leaflet.js library. Manipulate your data in Python, then visualize it in on a Leaflet map via folium.
56 |
57 | See [folium_webmaps.py](folium_webmaps.py)
58 |
59 |
60 | ## Plotly
61 |
62 | [Plotly](https://plotly.com/python/) is an open source python graphing library
63 |
64 |
65 | ## ggplot
66 |
67 | > [ggplot](http://ggplot.yhathq.com/) is a plotting system for Python based on R's ggplot2 and the Grammar of Graphics. It is built for making professional looking, plots quickly with minimal code.
68 |
69 |
70 | ## VisPy
71 |
72 | > [VisPy](http://vispy.org/) VisPy is a Python library for interactive scientific visualization that is designed to be fast, scalable, and easy to use.
73 |
74 | ## Altair
75 |
76 | > [Altair](https://altair-viz.github.io/) is a declarative statistical visualization library for Python, based on Vega and Vega-Lite, and the source is available on GitHub.
77 |
78 |
79 | ## Data Sources
80 |
81 | - [Top 8 Weather APIs](https://www.climacell.co/blog/top-8-weather-apis-for-2020/)
82 | - [Historical weather data - Weather Underground](https://www.wunderground.com/history/)
83 | - [National Centres for Environmental Information](https://www.ncdc.noaa.gov/data-access/quick-links)
84 | - [Historical Climate Data - Government of Canada](http://climate.weather.gc.ca/index_e.html)
85 |
--------------------------------------------------------------------------------
/dataclasses_module.py:
--------------------------------------------------------------------------------
1 | '''Data Classes'''
2 |
3 |
4 | # https://docs.python.org/3.7/library/dataclasses.html#module-dataclasses
5 |
6 | # Python 3.7 introduced a new module: dataclasses.py. The new dataclass()
7 | # decorator provides a way to declare data classes. A data class is a class
8 | # that typically contains mainly data. When you use it, the class constructor
9 | # (__init__ method) and other magic methods, such as __repr__(), __eq__(), and
10 | # __hash__() are generated automatically.
11 |
12 | # When using this decorator, you need to describe the attributes using
13 | # class variable annotations - type hints (introduced in Python 3.6).
14 |
15 | # Example:
16 |
17 | from dataclasses import dataclass
18 |
19 | @dataclass
20 | class Point():
21 | x: float
22 | y: float
23 | z: float = 0.0
24 |
25 | p = Point(1.5, 2.5)
26 | print(p) # Point(x=1.5, y=2.5, z=0.0)
27 |
28 |
29 | # Annotationg varibales
30 | # ------------------------------------------------------------------------------
31 | # Python 3.6 introduced a syntax for annotating variables in PEP 526.
32 | # Here's a quick review. For more see documenting_naming.py
33 |
34 | # For simple built-in types:
35 | x: int = 1
36 | x: float = 1.0
37 | x: bool = True
38 | x: str = 'test'
39 | x: bytes = b'test'
40 |
41 | from typing import List, Set, Dict, Tuple, Optional
42 |
43 | x: List[int] = [1]
44 | x: Set[int] = {6, 7}
45 | x: Dict[str, float] = {'field': 2.0}
46 | x: Tuple[int, str, float] = (3, "yes", 7.5)
47 | # x: Optional[str] = some_function()
48 |
49 |
50 | # dataclass() parameters
51 | # ------------------------------------------------------------------------------
52 | # The dataclass decorator has some default parameters:
53 |
54 | @dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
55 | class Example():
56 | pass
57 |
58 | # init: If true (the default), a __init__() method will be generated. If the
59 | # class already defines __init__(), this parameter is ignored.
60 |
61 | # repr: If true (the default), a __repr__() method will be generated. The
62 | # generated string will have the class name and the name and repr of each field,
63 | # in the order they are defined in the class. Fields can be marked to be excluded
64 | # from the repr. If the class defines __repr__(), this parameter is ignored.
65 |
66 | # eq: If true (the default), an __eq__() method will be generated. This method
67 | # compares the class as if it were a tuple of its fields, in order. Both
68 | # instances in the comparison must be of the identical type. If the class
69 | # already defines __eq__(), this parameter is ignored.
70 |
71 | # order: If true (the default is False), __lt__(), __le__(), __gt__(), and
72 | # __ge__() methods will be generated. Works the same as eq. Note if order is
73 | # true and eq is false, a ValueError is raised.
74 |
75 | # unsafe_hash: If False (the default), a __hash__() method is generated
76 | # according to how eq and frozen are set. __hash__() is used by built-in hash(),
77 | # and when objects are added to hashed collections such as dictionaries and sets.
78 | # Having a __hash__() implies that instances of the class are immutable. For an
79 | # in depth explanation see the docs.
80 |
81 | # frozen: If true (the default is False), assigning to fields will generate an
82 | # exception. This emulates read-only frozen instances. If __setattr__() or
83 | # __delattr__() is defined in the class, then a TypeError is raised.
84 |
85 |
86 | # field()
87 | # ------------------------------------------------------------------------------
88 | # This method allows us to add more information to a particular attribute.
89 | # The parameters to field() are:
90 |
91 | # default: If provided, this will be the default value for this field. This is
92 | # needed because the field() call itself replaces the normal position where the
93 | # default value would go.
94 |
95 | # default_factory: If provided, it must be a zero-argument callable that will
96 | # be called when a default value is needed for this field. Among other purposes,
97 | # this can be used to specify fields with mutable default values.
98 |
99 | # init: If true (the default), this field is included as a parameter to the
100 | # generated __init__() method.
101 |
102 | # repr: If true (the default), this field is included in the string returned
103 | # by the generated __repr__() method.
104 |
105 | # compare: If true (the default), this field is included in the generated
106 | # equality and comparison methods (__eq__(), __gt__(), et al.).
107 |
108 | from dataclasses import field
109 |
110 | @dataclass
111 | class InventoryItem():
112 | '''Class representing an item in inventory.'''
113 | name: str
114 | price: float
115 | rating: int = field(repr=False)
116 | quantity: int = 0
117 | min: int = field(repr=False, default=10)
118 | mylist: List[int] = field(default_factory=list)
119 |
120 | def total_value(self):
121 | return self.price * self.quantity
122 |
123 |
124 | i = InventoryItem('pencils', 0.5, 5, 100)
125 | i.mylist += [10]
126 | i.mylist += [20, 2]
127 |
128 | print(i)
129 | # InventoryItem(name='pencils', price=0.5, quantity=100, mylist=[10, 20, 2])
130 | print(i.total_value())
131 | # 50.0
132 | print(i.rating)
133 | # 5
134 |
135 |
136 | # fields(), asdict(), astuple(), is_dataclass()
137 | # ------------------------------------------------------------------------------
138 |
139 | from dataclasses import fields, asdict, astuple, is_dataclass
140 | from pprint import pprint
141 |
142 | # This method returns a tuple of field objects for a given dataclass.
143 | pprint(fields(i))
144 | #TL;DR
145 |
146 | # This method returns a dict of fields for a given dataclass.
147 | pprint(asdict(i))
148 | # {'min': 10,
149 | # 'mylist': [10, 20, 2],
150 | # 'name': 'pencils',
151 | # 'price': 0.5,
152 | # 'quantity': 100,
153 | # 'rating': 5}
154 |
155 | # This method returns a tuple of fields for a given dataclass.
156 | pprint(astuple(i))
157 | # ('pencils', 0.5, 5, 100, 10, [10, 20, 2])
158 |
159 | # This method returns True if the given arg is a dataclass or instance of one.
160 | pprint(is_dataclass(i))
161 | # True
162 |
--------------------------------------------------------------------------------
/date_time_examples.py:
--------------------------------------------------------------------------------
1 | '''datetime Examples'''
2 |
3 |
4 | # Compare usages
5 | # -----------------------------------------------------------------------------
6 |
7 | import datetime
8 | import pytz
9 |
10 | now = datetime.datetime.now()
11 | # 2017-10-02 16:03:01.558993
12 |
13 | utc = datetime.datetime.utcnow()
14 | # 2017-10-02 23:03:01.559071
15 |
16 | the_time = pytz.utc.localize(datetime.datetime.utcnow())
17 | # 2017-10-02 23:03:01.559084+00:00
18 |
19 | the_local_time = the_time.astimezone()
20 | # 2017-10-02 16:03:01.559084-07:00
21 |
22 | the_local_time = pytz.utc.localize(datetime.datetime.utcnow()).astimezone()
23 | # 2017-10-02 16:03:01.559084-07:00
24 |
25 | timezone = the_local_time.tzinfo
26 | # PDT
27 |
28 | formatted = datetime.datetime.now().strftime('%m-%d-%Y, %H:%M %p')
29 | # 12-31-2017, 10:47 AM
30 |
31 | timestamp = datetime.datetime.now().strftime('%a %x')
32 | # Mon 10/02/17
33 |
34 | backdated = datetime.date(2017, 8, 7).strftime('%a %x')
35 | # Mon 08/07/17
36 |
37 | print(f'{now.month}/{now.day}/{now.year}')
38 | # 1/5/2022
39 |
40 |
41 | # timedelta example
42 | # -----------------------------------------------------------------------------
43 | # The following function will output a plant watering schedule using the
44 | # datetime timedelta method.
45 |
46 | from datetime import date
47 | from datetime import timedelta
48 |
49 | def watering_schedule(x):
50 | '''Calculate a plant watering schedule for the next 'x' waterings'''
51 | # categorize each month into seasons:
52 | winter_months = [1, 2, 3, 12]
53 | summer_months = [6, 7, 8, 9]
54 | # watering frequency every n days:
55 | winter_freq = 6
56 | spring_fall_freq = 5
57 | summer_freq = 4
58 | # check the month and generate schedule:
59 | now = date.today()
60 | schedule = []
61 | while len(schedule) < x:
62 | if now.month in summer_months:
63 | now += timedelta(days=summer_freq)
64 | schedule.append(now)
65 | elif now.month in winter_months:
66 | now += timedelta(days=winter_freq)
67 | schedule.append(now)
68 | else:
69 | now += timedelta(days=spring_fall_freq)
70 | schedule.append(now)
71 | print('Watering Schedule:')
72 | for i in schedule:
73 | print(i)
74 |
75 | watering_schedule(25)
76 |
--------------------------------------------------------------------------------
/debugging.py:
--------------------------------------------------------------------------------
1 | '''Debugging'''
2 |
3 |
4 | # General Tips
5 | # -----------------------------------------------------------------------------
6 | # Though not very advanced, dropping print() statements and other reflection
7 | # related functions can tell you a lot about what's going on. Beyond that:
8 |
9 | # print the values of your local arguments with:
10 |
11 | print(vars())
12 |
13 | # If you run your program with an -i flag, it will drop you into the
14 | # interactive interpreter if the program fails:
15 |
16 | # $ python3 -i myfile.py
17 |
18 |
19 | # Standard Library: pdb module
20 | # -----------------------------------------------------------------------------
21 | # Bug test: read a file of countries and their capital cities, separated by a
22 | # comma, and write them out as capital, country. In addition:
23 | # – Make sure they capitalized incorrectly
24 | # – Remove any extra spaces extra spaces
25 | # – Stop the program if we find the word quit (uppercase or lowercase)
26 |
27 | # Here's a sample data file data/cities.csv:
28 | '''
29 | France, Paris
30 | venuzuela,caracas
31 | LithuniA,vilnius
32 | argentina,buenos aires
33 | bolivia,la paz
34 | brazil,brasilia
35 | chile,santiago
36 | colombia,Bogotá
37 | ecuador,quito
38 | falkland islands,stanley
39 | french guiana,cayenne
40 | guyana,georgetown
41 | paraguay,Asunción
42 | peru,lima
43 | suriname,paramaribo
44 | uruguay,montevideo
45 | venezuela,caracas
46 | quit
47 | '''
48 |
49 | # Here's pseudocode:
50 | '''
51 | for each line in the text file:
52 | read the line
53 | strip leading and trailing spaces
54 | if 'quit' occurs in a lowercase copy of the line:
55 | stop
56 | else:
57 | split the country and capital by the comma character
58 | trim any leading and trailing spaces
59 | convert the country and capital to titlecase
60 | print the capital, a comma, and the country
61 | '''
62 |
63 |
64 | # Here's the actual code:
65 | def process_cities(filename):
66 | with open(filename, 'rt') as file:
67 | for line in file:
68 | line = line.strip()
69 | if 'quit' in line.lower(): # should be if 'quit' == line.lower():
70 | return
71 | country, city = line.split(',')
72 | city = city.strip()
73 | country = country.strip()
74 | print(city.title(), country.title(), sep=',')
75 |
76 |
77 | # import pdb; pdb.set_trace() # this will launch the debugger
78 | breakpoint() # this will launch the debugger as of Python 3.7
79 |
80 | process_cities('data/cities.csv')
81 |
82 |
83 | # pdb Commands
84 | # -----------------------------------------------------------------------------
85 | # Documented commands (type help ):
86 |
87 | # EOF c d h list q rv undisplay
88 | # a cl debug help ll quit s unt
89 | # alias clear disable ignore longlist r source until
90 | # args commands display interact n restart step up
91 | # b condition down j next return tbreak w
92 | # break cont enable jump p retval u whatis
93 | # bt continue exit l pp run unalias where
94 |
95 | # type 'c' to continue (the program will run until it ends normally or via
96 | # an Error/Exception). If it ends normally, we now it's logic error
97 | # rather than a syntax error.
98 | # type 's' single step through lines and into functions/methods
99 | # (this will include any modules you might be using like sys)
100 | # type 'n' to step past a function/method (execute and move onto the next).
101 | # Generally speaking you would 'n' to step past any library code.
102 | # type 'l' to see the next few lines at once
103 | # type 'll' to see even more of the next few lines at once
104 | # type 'l' and a line number to see lines from that point onward
105 | # type 'b' and a line number to insert a breakpoint
106 | # type 'b' alone to see all your breakpoints
107 | # type 'cl' and a number to (clear) a breakpoint
108 |
109 | # NOTE: Your program will ONLY stop at a breakpoint if it has a chance to
110 | # actually get to that spot in the code.
111 |
112 | # type 'u' to go up (back)
113 | # type 'p' to print the value of something. i.e. p line
114 | # type a variable name and it will output its current value
115 | # type '?' or help when in the pdb to see all the commands.
116 | # type help command to get help on that one.
117 |
118 | # NOTE: when viewing lines, 'B' indicates a breakpoint you've inserted and
119 | # '->' indicates your current line
120 |
121 | # To use the debugger from the command line, import the pdb module by typing:
122 | # $ python3 -m pdb myfile.py
123 |
124 | # For the example above if we drop a breakpoint at line 68 and continue our
125 | # program, when it stops if we type line to see the current value of line we
126 | # see our problem: ecuador,quito.
127 |
128 |
129 | # breakpoint(*args, **kws)
130 | # ------------------------------------------------------------------------------
131 | # New to Python 3.7, this function drops you into the debugger where ever you
132 | # call it in your code. Specifically, it calls sys.breakpointhook(), passing
133 | # *args and **kws straight through. By default, sys.breakpointhook() calls
134 | # pdb.set_trace() expecting no arguments. It is purely a convenience function
135 | # so you don’t have to explicitly import pdb or type as much code to enter the
136 | # debugger.
137 |
138 | images = ['pickle.png', 'dog.jpg', 'car.png', 'apple.gif', 'baloon.psd']
139 | todo = []
140 |
141 | for i in images:
142 | if not i.endswith('.png'):
143 | breakpoint()
144 | todo.append(i)
145 |
146 | print(todo)
147 |
--------------------------------------------------------------------------------
/decorators.py:
--------------------------------------------------------------------------------
1 | '''Decorators'''
2 |
3 |
4 | # A decorator is a function that takes one function as an input and returns
5 | # another function. Here is a simplified example:
6 |
7 | def my_decorator(func):
8 | def wrapper(arg):
9 | print('Before {}() is called.'.format(func.__name__))
10 | func(arg)
11 | print('After {}() is called.'.format(func.__name__))
12 | return wrapper
13 |
14 | @my_decorator
15 | def squares(n):
16 | '''returns the square of a number'''
17 | print(n ** 2)
18 |
19 | squares(6)
20 | # Before squares() is called.
21 | # 36
22 | # After squares() is called.
23 |
24 |
25 | # @functools.wraps():
26 | # -----------------------------------------------------------------------------
27 | # When you use a decorator, you're replacing one function (squares) with
28 | # another (wrapper). While inside the decorator we can see the original
29 | # function being used but now when outside, look what happens:
30 |
31 | print(squares.__name__) # wrapper
32 | print(squares.__doc__) # None
33 |
34 | # That's why we have functools.wraps. This takes a function used in a decorator
35 | # and adds the functionality of copying over the functions name, docstring,
36 | # arguments list, etc. See the difference:
37 |
38 | from functools import wraps
39 |
40 | def my_decorator(func):
41 | @wraps(func) # Add this, everything else is the same
42 | def wrapper(arg):
43 | print('Before {}() is called.'.format(func.__name__))
44 | func(arg)
45 | print('After {}() is called.'.format(func.__name__))
46 | return wrapper
47 |
48 | @my_decorator
49 | def squares(n):
50 | '''returns the square of a number'''
51 | print(n ** 2)
52 |
53 | print(squares.__name__) # squares
54 | print(squares.__doc__) # returns the square of a number
55 |
56 |
57 | # Returning results
58 | # -----------------------------------------------------------------------------
59 | # The function document_it() below defines a decorator that will:
60 | # - print the functions name and values of its arguments
61 | # - run the function with the arguments
62 | # - print the result
63 | # - return the modified function for use
64 |
65 | def document_it(func):
66 | @wraps(func)
67 | def wrapper(*args, **kwargs):
68 | print('Running function:', func.__name__)
69 | print('Positional arguments:', args)
70 | print('Keyword arguments:', kwargs)
71 | result = func(*args, **kwargs)
72 | print('Result:', result)
73 | return result
74 | return wrapper
75 |
76 | # Here's our simple test function, first we'll run it without a decorator:
77 | def add_multiply(a, b, multiplyer=1):
78 | return (a + b) * multiplyer
79 |
80 | decorated_add_ints = document_it(add_multiply)
81 | decorated_add_ints(3, 5, multiplyer=100)
82 | # Running function: add_multiply
83 | # Positional arguments: (3, 5)
84 | # Keyword arguments: {'multiplyer': 100}
85 | # Result: 800
86 |
87 | # Now with a decorator... a little less code:
88 | @document_it
89 | def add_multiply(a, b, multiplyer=1):
90 | return (a + b) * multiplyer
91 |
92 | add_multiply(4, 5, multiplyer=100)
93 | # Running function: add_multiply
94 | # Positional arguments: (4, 5)
95 | # Keyword arguments: {'multiplyer': 100}
96 | # Result: 900
97 |
98 |
99 | # Multiple decorators
100 | # -----------------------------------------------------------------------------
101 |
102 | def square_it(func):
103 | @wraps(func)
104 | def wrapper(*args, **kwargs):
105 | result = func(*args, **kwargs)
106 | return result * result
107 | return wrapper
108 |
109 | # The decorator that's closest to the actual function (above the def) runs
110 | # first and then the one above that will run. The results will be the same no
111 | # matter what order but the intermediate steps are different. Depending on what
112 | # your decorators do, the order may be important.
113 |
114 | @document_it
115 | @square_it
116 | def add_ints(a, b):
117 | return a + b
118 |
119 | print(add_ints(4, 3))
120 | # Running function: add_ints
121 | # Positional arguments: (4, 3)
122 | # Keyword arguments: {}
123 | # Result: 49
124 | # 49
125 |
126 | @square_it
127 | @document_it
128 | def add_ints(a, b):
129 | return a + b
130 |
131 | print(add_ints(4, 3))
132 | # Running function: add_ints
133 | # Positional arguments: (4, 3)
134 | # Keyword arguments: {}
135 | # Result: 7
136 | # 49
137 |
138 |
139 | # @property
140 | # -----------------------------------------------------------------------------
141 | # see decorators used as getter and setter methods in classes.py
142 |
143 |
144 | # decorators with arguments
145 | # -----------------------------------------------------------------------------
146 | # Consider this example. Imagine a number of functions that allow access to
147 | # different things, but you only want to allow access if some criteria is met.
148 | # Instead of repeating code in each function, you can set this up in a
149 | # decorator. The only problem is, for some reason you can't add parameters to
150 | # the decorator that has (func) passed in. So in order to do this, we have to
151 | # create another wrapping decorator :(
152 |
153 | def bouncer(flag):
154 | def my_decorator(func):
155 | @wraps(func)
156 | def wrapper(*args, **kwargs):
157 | if flag:
158 | func(*args, **kwargs)
159 | else:
160 | print('Not running the function')
161 | return wrapper
162 | return my_decorator
163 |
164 | flag = True
165 |
166 | @bouncer(flag)
167 | def my_function():
168 | print('The function runs...')
169 |
170 | my_function()
171 | # The function runs...
172 |
173 | flag = False
174 |
175 | @bouncer(flag)
176 | def my_function():
177 | print('The function runs...')
178 |
179 | my_function()
180 | # Not running the function
181 |
182 |
183 | # one last example:
184 | # -----------------------------------------------------------------------------
185 |
186 | import time
187 |
188 | def timing(func):
189 | '''Outputs the time a function takes to execute.'''
190 | @wraps(func)
191 | def wrapper(*args, **kwargs):
192 | t1 = time.time()
193 | func(*args, **kwargs)
194 | t2 = time.time()
195 | return 'Time it took to run the function: ' + str((t2 - t1))
196 | return wrapper
197 |
198 | @timing
199 | def my_function():
200 | num_list = []
201 | for num in (range(0, 10000)):
202 | num_list.append(num)
203 |
204 | print(my_function())
205 | # Time it took to run the function: 0.0011439323425292969
206 |
--------------------------------------------------------------------------------
/demos/redis_dryer.py:
--------------------------------------------------------------------------------
1 | # import redis
2 | #
3 | # conn = redis.Redis()
4 | # print('Dryer is starting')
5 | #
6 | # while True:
7 | # msg = conn.blpop('dishes')
8 | # if not msg:
9 | # break
10 | # val = msg[1].decode('utf-8')
11 | # if val == 'quit':
12 | # break
13 | # print('dried', val)
14 | #
15 | # print('Dryer is done')
16 |
17 |
18 |
19 | def dryer():
20 | import redis
21 | import os
22 | import time
23 | conn = redis.Redis()
24 | pid = os.getpid()
25 | timeout = 20
26 | print('Dryer process {} is starting'.format(pid))
27 |
28 | while True:
29 | msg = conn.blpop('dishes', timeout)
30 | if not msg:
31 | break
32 | val = msg[1].decode('utf-8')
33 | if val == 'quit':
34 | break
35 | print('{} dried {}'.format(pid, val))
36 | time.sleep(0.1)
37 | print('dryer process {} is done'.format(pid))
38 |
39 | import multiprocessing
40 | DRYERS = 3
41 | for num in range(DRYERS):
42 | p = multiprocessing.Process(target=dryer)
43 | p.start()
44 |
--------------------------------------------------------------------------------
/demos/redis_pub.py:
--------------------------------------------------------------------------------
1 | import random
2 | import redis
3 |
4 | conn = redis.Redis()
5 | cats = ['siamese', 'black', 'persian', 'main coon', 'tabby', 'norwegian']
6 | hats = ['bowler', 'fedora', 'top hat', 'poor boy', 'cowboy', 'stovepipe']
7 |
8 | for i in range(10):
9 | cat = random.choice(cats)
10 | hat = random.choice(hats)
11 | print('Publish: {} cat wears a {}'.format(cat, hat))
12 | conn.publish(cat, hat)
13 |
--------------------------------------------------------------------------------
/demos/redis_sub.py:
--------------------------------------------------------------------------------
1 | import redis
2 |
3 | conn = redis.Redis()
4 | topics = ['siamese', 'black']
5 | sub = conn.pubsub()
6 | sub.subscribe(topics)
7 |
8 | for msg in sub.listen():
9 | if msg['type'] == 'message':
10 | cat = msg['channel']
11 | hat = msg['data']
12 | print('Subscribe: {} cat wears a {}'.format(cat, hat))
13 |
--------------------------------------------------------------------------------
/demos/redis_washer.py:
--------------------------------------------------------------------------------
1 | import redis
2 |
3 | conn = redis.Redis()
4 | print('Washer is starting')
5 | dishes = ['salad', 'bread', 'main', 'side', 'dessert']
6 |
7 | for dish in dishes:
8 | msg = dish.encode('utf-8')
9 | conn.rpush('dishes', msg)
10 | print('washed', dish)
11 |
12 | conn.rpush('dishes', 'quit')
13 | print('Washer is done')
14 |
--------------------------------------------------------------------------------
/demos/sample_plot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jessicarush/python-notes/124f21c82f2a249e0413a3c3e3c01ff8d7b46481/demos/sample_plot.png
--------------------------------------------------------------------------------
/demos/tasks.py:
--------------------------------------------------------------------------------
1 | # This demo file goes with the instructions in queues.py
2 |
3 | import time
4 |
5 | def example(seconds):
6 | print('Starting task...')
7 | for i in range(seconds):
8 | print(i)
9 | time.sleep(1)
10 | print('Task completed.')
--------------------------------------------------------------------------------
/demos/tasks_with_info.py:
--------------------------------------------------------------------------------
1 | # This demo file goes with the instructions in queues.py
2 |
3 | import time
4 | from rq import get_current_job
5 |
6 | def example(seconds):
7 | job = get_current_job()
8 | print('Starting task...')
9 | for i in range(seconds):
10 | job.meta['progress'] = 100.0 * i / seconds
11 | job.save_meta()
12 | print(i)
13 | time.sleep(1)
14 | job.meta['progress'] = 100
15 | job.save_meta()
16 | print('Task completed.')
--------------------------------------------------------------------------------
/demos/tcp_client.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import socket
3 |
4 |
5 | address = ('localhost', 4544)
6 | max_size = 1000
7 | print('Starting the client at', datetime.datetime.now())
8 |
9 | client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
10 |
11 | # The connect() call sets up a stream
12 | client.connect(address)
13 | client.sendall(b'Hi there')
14 | data = client.recv(max_size)
15 | print('Message:', datetime.datetime.now(), 'someone replied', data)
16 |
17 | client.close()
18 |
--------------------------------------------------------------------------------
/demos/tcp_server.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import socket
3 |
4 |
5 | address = ('localhost', 4544)
6 | max_size = 1000 # bytes
7 | print('Starting the server at', datetime.datetime.now())
8 | print('waiting for client to call')
9 |
10 | # SOCK_DGRAM is replaced with SOCK_STREAM to use the streaming TCP protocol:
11 | server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
12 | server.bind(address)
13 |
14 | # This queues up to 5 client connections before refusing new ones:
15 | server.listen(5)
16 |
17 | # TCP gets the first available message as it arrives:
18 | client, addr = server.accept()
19 | data = client.recv(max_size)
20 | print('Message:', datetime.datetime.now(), client, 'said', data)
21 |
22 | client.sendall(b'Are you talking to me?')
23 | client.close()
24 | server.close()
25 |
--------------------------------------------------------------------------------
/demos/udp_client.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import socket
3 |
4 |
5 | server_address = ('localhost', 4544)
6 | max_size = 4096
7 | print('Starting the client at', datetime.datetime.now())
8 |
9 | client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
10 |
11 | client.sendto(b'Hello', server_address)
12 |
13 | data, server = client.recvfrom(max_size)
14 | print('Message:', datetime.datetime.now(), server, 'said', data)
15 |
16 | client.close()
17 |
--------------------------------------------------------------------------------
/demos/udp_server.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import socket
3 |
4 |
5 | server_address = ('localhost', 4544)
6 | max_size = 4096
7 | print('Starting the server at', datetime.datetime.now())
8 | print('waiting for client to call')
9 |
10 | # This line creates a socket (AF_INET means we'll create an IP socket,
11 | # SOCK_DGRAM means we'll send and receive datagrams - UDP):
12 | server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
13 |
14 | # This listens for any data arriving at the IP, port. The programs sits and
15 | # waits here until there's some action:
16 | server.bind(server_address)
17 |
18 | # Any data that comes in will be received here:
19 | data, client = server.recvfrom(max_size)
20 | print('Message:', datetime.datetime.now(), client, 'said', data)
21 |
22 | # The server sends a reply:
23 | server.sendto(b'Are you talking to me?', client)
24 |
25 | # and closes the connection:
26 | server.close()
27 |
--------------------------------------------------------------------------------
/escape_characters.py:
--------------------------------------------------------------------------------
1 | '''Escape Characters'''
2 |
3 |
4 | # Backslash allows you to escape characters or run an escape sequence
5 | # for example, escape the single-quote inside the string:
6 |
7 | print('I am 6\'2" tall.')
8 |
9 | # using triple quotes also works """
10 |
11 | # \\ = backslash
12 | # \' = single quote
13 | # \" = double quote
14 | # \a = ASCII bell
15 | # \b = ASCII backspace
16 | # \f = ASCII formfeed
17 | # \n = ASCII line break
18 | # \r = ASCII full return
19 | # \t = ASCII tab
20 | # \v = ASCII vertical tab
21 | # \N{name} = unicode character name in the unicode database
22 | # \uxxxx = unicode character with 16-bit hex value xxxx
23 | # \Uxxxxxxxx = unicode character with 32-bit hex value xxxxxxxx
24 | # \ooo = character with octal value ooo
25 | # \xhh... = character with hex value hh..
26 |
27 | # Example:
28 |
29 | print('Escape characters:\n\t-\u272D')
30 | # Escape characters:
31 | # -✭
32 |
--------------------------------------------------------------------------------
/flask_mqtt.md:
--------------------------------------------------------------------------------
1 | # Flask-mqtt
2 |
3 | See the [flask-mqtt documentation](https://flask-mqtt.readthedocs.io/en/latest/api/index.html)
4 | See also: [MQTT Essentials](https://www.hivemq.com/blog/mqtt-essentials-part-4-mqtt-publish-subscribe-unsubscribe/)
5 |
6 | ## Table of contents
7 |
8 |
9 |
10 | - [Introduction](#introduction)
11 | - [Install](#install)
12 | - [Instantiate and include](#instantiate-and-include)
13 | - [Client side](#client-side)
14 | - [Server side](#server-side)
15 | - [Notes](#notes)
16 | - [Mosquitto broker](#mosquitto-broker)
17 |
18 |
19 |
20 | ## Introduction
21 |
22 | MQTT is a lightweight, publish-subscribe network protocol that transports messages between devices using an MQTT broker.
23 |
24 | A client can publish messages as soon as it connects to a broker. Each message contains a topic that the broker uses to forward the message to interested clients. To receive messages on topics, a client sends a subscribe message to the MQTT broker.
25 |
26 | When a client sends a message to an MQTT broker for publication, the broker reads the message, acknowledges it (according to the Quality of Service [QoS] Level), and sends it off to the clients who have subscribed to the topic.
27 |
28 | The client that initially publishes the message is only concerned about delivering the message to the broker. Once the broker receives the message, it is the responsibility of the broker to deliver the message to all subscribers. The publishing client does not get any feedback about whether anyone is interested in the published message or how many clients received the message from the broker.
29 |
30 | ## Install
31 |
32 | ```
33 | pip install flask-mqtt
34 | ```
35 |
36 | ## Instantiate and include
37 |
38 | `__init__.py`
39 | ```python
40 | from flask_mqtt import Mqtt
41 |
42 | app = Flask(__name__)
43 | mqtt = Mqtt(app, connect_async=True) # To address flask-mqtt issue #73
44 | ```
45 |
46 | `run.py`
47 | ```python
48 | socketio.run(app,
49 | host='0.0.0.0',
50 | port=80,
51 | debug=True,
52 | use_reloader=False, # mqtt requires this
53 | certfile='cert.pem',
54 | keyfile='key.pem')
55 | ```
56 |
57 | `routes.py`
58 | ```python
59 | from app import mqtt
60 | ```
61 |
62 | `config.py`
63 | ```python
64 | # MQTT configuration variables
65 | MQTT_BROKER_URL = 'localhost'
66 | MQTT_BROKER_PORT = 1883
67 | MQTT_USERNAME = ''
68 | MQTT_PASSWORD = ''
69 | MQTT_KEEPALIVE = 10
70 | MQTT_TLS_ENABLED = False
71 | ```
72 |
73 | See the [flask-mqtt docs](https://flask-mqtt.readthedocs.io/en/latest/configuration.html#configuration-keys) for a complete list of the config keys.
74 |
75 | ## Client side
76 |
77 | All socketio
78 |
79 | ## Server side
80 |
81 | ```python
82 | # subscribe to a topic as soon as mqtt is connected
83 | @mqtt.on_connect()
84 | def handle_connect(client, userdata, flags, rc):
85 | mqtt.subscribe('home/mytopic')
86 |
87 | # handle the subscribed messages
88 | @mqtt.on_message()
89 | def handle_mqtt_message(client, userdata, message):
90 | data = dict(
91 | topic=message.topic,
92 | payload=message.payload.decode()
93 | )
94 |
95 | # unsubscribe
96 | mqtt.unsubscribe('home/mytopic')
97 | mqtt.unsubscribe_all()
98 |
99 | # publish a message
100 | mqtt.publish('home/mytopic', 'this is my message')
101 | ```
102 |
103 | ## Notes
104 |
105 | - A subscribe message can contain multiple subscriptions for a client. Each subscription is made up of a topic and a QoS level.
106 |
107 | - The topic in the subscribe message can contain wildcards that make it possible to subscribe to a topic pattern rather than a specific topic.
108 |
109 | - If there are overlapping subscriptions for one client, the broker delivers the message that has the highest QoS level for that topic.
110 |
111 | - The broker holds the session data of all clients that have persistent sessions, including subscriptions and missed messages.
112 |
113 | - Published messages have a Retain Flag (true/false). This flag defines whether the message is saved by the broker as the last known good value for a specified topic. When a new client subscribes to a topic, they receive the last message that is retained on that topic.
114 |
115 | - $ topics are reserved for internal statistics of the MQTT broker, for example:
116 | ```
117 | $SYS/broker/clients/connected
118 | $SYS/broker/clients/disconnected
119 | $SYS/broker/clients/total
120 | $SYS/broker/messages/sent
121 | $SYS/broker/uptime
122 | ```
123 |
124 | - A retained message is a normal MQTT message with the retained flag set to true. Using retained messages helps provide the last good value to a connecting client immediately.
125 |
126 | - The clean session flag tells the broker whether the client wants to establish a persistent session or not. In a persistent session (CleanSession = false), the broker stores all subscriptions for the client and all missed messages for the client that subscribed with a Quality of Service (QoS) level 1 or 2. If the session is not persistent (CleanSession = true), the broker does not store anything for the client and purges all information from any previous persistent session. Note in the Flask-MQTT github readme example, they have a config: `app.config['MQTT_CLEAN_SESSION'] = True` but this config is missing from the documentation.
127 |
128 | - In MQTT, you use the Last Will and Testament (LWT) feature to notify other clients about an ungracefully disconnected client. Each client can specify its last will message when it connects to a broker. The last will message is a normal MQTT message with a topic, retained message flag, QoS, and payload. The broker stores the message until it detects that the client has disconnected ungracefully. In response to the ungraceful disconnect, the broker sends the last-will message to all subscribed clients of the last-will message topic. If the client disconnects gracefully with a correct DISCONNECT message, the broker discards the stored LWT message. Clients can specify an LWT message in the CONNECT message that initiates the connection between the client and the broker.
129 |
130 |
131 | ## Mosquitto broker
132 |
133 | To restart the broker:
134 | ```
135 | sudo systemctl restart mosquitto
136 | ```
137 |
138 | To clear out (reset) the broker
139 | ```
140 | sudo systemctl stop mosquitto
141 | sudo rm /var/lib/mosquitto/mosquitto.db
142 | sudo systemctl start mosquitto
143 | ```
144 |
145 | To publish via the command line:
146 | ```
147 | mosquitto_pub -t "xnet/sts/scc1/status" -m "offline"
148 | ```
149 |
150 | To subscribe via the command line:
151 | ```
152 | mosquitto_sub -t "xnet/sts/scc1/status"
153 | ```
154 |
--------------------------------------------------------------------------------
/flask_user_roles.md:
--------------------------------------------------------------------------------
1 | # User Roles in Flask
2 |
3 | There are a number of ways of implementing user roles in a Flask app. The best method will largely depend on how many different roles need to be supported and how elaborate they are. For example, a simple app may need only two roles, regular users and admin. In this case, having a simple `is_admin` boolean in the `User` model may be all that is necessary.
4 |
5 | In more complex apps, you may need several roles with varying levels of access. In some cases it may make more sense to discard the idea of individual roles and instead give users a set of individual permissions.
6 |
7 | ## Table of contents
8 |
9 |
10 |
11 | - [Simple Solution 1 - limit access in templates](#simple-solution-1---limit-access-in-templates)
12 | - [Simple Solution 2 - limit access in routes using redirects](#simple-solution-2---limit-access-in-routes-using-redirects)
13 | - [Roles & permissions - Chapter 9 Flask Web directive](#roles--permissions---chapter-9-flask-web-directive)
14 | - [User roles - Flask-User library](#user-roles---flask-user-library)
15 |
16 |
17 |
18 | ## Simple Solution 1 - limit access in templates
19 |
20 | In any Jinja template, you could pass the user data and show different things depending on the access level.
21 |
22 | For example:
23 |
24 | ```Jinja
25 | {% if current_user.is_admin %}
26 | ...Admin only content...
27 | {% endif %}
28 | ```
29 |
30 | This is safe because the templates are rendered in the server. The user cannot modify their access level or show and hide elements through the Developer Tools in the browser.
31 |
32 | ## Simple Solution 2 - limit access in routes using redirects
33 |
34 | In any endpoint, you could check for a condition and simply redirect if it is not met.
35 |
36 | For example:
37 |
38 | ```python
39 | @app.route('/admin')
40 | def admin():
41 | '''View function for the admins only.'''
42 | if not current_user.is_admin:
43 | flash('Sorry, only admins can access that page.', category='auth-fail')
44 | return redirect(url_for('index'))
45 | return render_template('admin.html')
46 | ```
47 |
48 | ## Roles & permissions - Chapter 9 Flask Web directive
49 |
50 | ## User roles - Flask-User library
51 |
--------------------------------------------------------------------------------
/geopy_module.py:
--------------------------------------------------------------------------------
1 | '''A Brief look at Geopy'''
2 |
3 |
4 | # https://geopy.readthedocs.io/en/stable/
5 |
6 | # geopy is a Python client for several popular geocoding web services. geopy
7 | # makes it easy to locate the coordinates of addresses, cities, countries, and
8 | # landmarks across the globe using third-party geocoders and other data sources.
9 |
10 | # geopy includes geocoder classes for: ArcGIS, AzureMaps, Baidu, BANFrance,
11 | # Bing, DataBC, GeocodeEarth, GeocodeFarm, Geolake, GeoNames, GoogleV3, HERE,
12 | # IGNFrance, MapBox, OpenCage, OpenMapQuest, Nominatim, Pelias, Photon,
13 | # PickPoint, LiveAddress, TomTom, What3Words, Yandex. The majority of these
14 | # require a (not free) API key or usernamename/password paramter. The various
15 | # geocoder classes are located in geopy.geocoders.
16 |
17 | # As of July 2018 Google requires each request to have a paid API key.
18 | # https://developers.google.com/maps/documentation/geocoding/usage-and-billing
19 |
20 | # $ pip install geopy
21 |
22 | # from geopy.geocoders import GoogleV3
23 | # from geopy.geocoders import Yandex
24 | # from geopy.geocoders import DataBC
25 | # from geopy.geocoders import Nominatim
26 | from geopy.geocoders import Photon
27 |
28 | # geolocator = GoogleV3(scheme='http')
29 | # geolocator = Yandex(lang='en', scheme='http')
30 | # geolocator = DataBC(scheme='http')
31 | # geolocator = Nominatim(scheme='http', user_agent='my-application')
32 | geolocator = Photon(scheme='http')
33 |
34 |
35 | address1 = '3995 23rd St, San Francisco, CA 94114, USA'
36 | address2 = '3730 Cambie St, Vancouver, BC V5Z2X5, Canada'
37 |
38 | location = geolocator.geocode(address1)
39 |
40 | print(type(location))
41 | #
42 |
43 | print(dir(location))
44 | # [... 'address', 'altitude', 'latitude', 'longitude', 'point', 'raw']
45 |
46 | print(location)
47 | # 3995 23rd St, San Francisco, CA 94114, USA
48 |
49 | print(location.address)
50 | # 3995 23rd St, San Francisco, CA 94114, USA
51 |
52 | print(location.altitude)
53 | # 0.0
54 |
55 | print((location.latitude, location.longitude))
56 | # (37.7529648, -122.4317141)
57 |
58 | print(location.point)
59 | # 37 45m 10.6733s N, 122 25m 54.1708s W
60 |
61 | print(location.raw)
62 | # {'address_components': [
63 | # {'long_name': '3995', 'short_name': '3995', 'types': ['street_number']},
64 | # {'long_name': '23rd Street', 'short_name': '23rd St', 'types': ['route']},
65 | # {'long_name': 'Noe Valley', 'short_name': 'Noe Valley', 'types':
66 | # ['neighborhood', 'political']},
67 | # {'long_name': 'San Francisco', 'short_name': 'SF', 'types':
68 | # ['locality', 'political']},
69 | # {'long_name': 'San Francisco County', 'short_name': 'San Francisco County',
70 | # 'types': ['administrative_area_level_2', 'political']},
71 | # {'long_name': 'California', 'short_name': 'CA', 'types':
72 | # ['administrative_area_level_1', 'political']},
73 | # {'long_name': 'United States', 'short_name': 'US', 'types':
74 | # ['country', 'political']},
75 | # {'long_name': '94114', 'short_name': '94114', 'types': ['postal_code']},
76 | # {'long_name': '3302', 'short_name': '3302', 'types': ['postal_code_suffix']}],
77 | # 'formatted_address': '3995 23rd St, San Francisco, CA 94114, USA',
78 | # 'geometry': {
79 | # 'location': {'lat': 37.7529353, 'lng': -122.4317224},
80 | # 'location_type': 'ROOFTOP',
81 | # 'viewport': {
82 | # 'northeast': {'lat': 37.75428428029149, 'lng': -122.4303734197085},
83 | # 'southwest': {'lat': 37.75158631970849, 'lng': -122.4330713802915}}},
84 | # 'place_id': 'ChIJp4irxxN-j4ARlJs-6IsSQGk', 'types': ['street_address']}
85 |
--------------------------------------------------------------------------------
/helper_functions.py:
--------------------------------------------------------------------------------
1 | '''Demo: Helper functions can be more readable than complex expressions.'''
2 |
3 |
4 | # Consider we're receiving some rgba values from a query string of a url.
5 | # The output we want is an integer for each r, g, b, and a. Let's say if the
6 | # values are missing, we want them to be 0.
7 |
8 | # Let's first see what type of data we get:
9 |
10 | from urllib.parse import parse_qs
11 |
12 | values = parse_qs('red=52&blue=0&green=', keep_blank_values=True)
13 |
14 | print(values)
15 | print(type(values))
16 | # {'red': ['52'], 'blue': ['0'], 'green': ['']}
17 | #
18 |
19 | # The get method will allow us to check for values even if they don't exist:
20 |
21 | red = values.get('red')
22 | green = values.get('green')
23 | blue = values.get('blue')
24 | opacity = values.get('opacity')
25 |
26 | print('red:', red)
27 | print('green:', green)
28 | print('blue:', blue)
29 | print('opacity:', opacity)
30 | # red: ['52']
31 | # green: ['']
32 | # blue: ['0']
33 | # opacity: None
34 |
35 | # So, if I just want the number, I would have to specfify the first item in the
36 | # list[0]. And if the list is empty I'd have to say 'or 0'. And if the value
37 | # didn't exist at all (None), then I'd have to pass an optional value to the
38 | # get method (an empty list):
39 |
40 | red = values.get('red', [''])[0] or 0
41 | green = values.get('green', [''])[0] or 0
42 | blue = values.get('blue', [''])[0] or 0
43 | opacity = values.get('opacity', [''])[0] or 0
44 |
45 | print('red:', red)
46 | print('green:', green)
47 | print('blue:', blue)
48 | print('opacity:', opacity)
49 | # red: 52
50 | # green: 0
51 | # blue: 0
52 | # opacity: 0
53 |
54 | # But I also have to make sure the values are integers:
55 |
56 | red = int(values.get('red', [''])[0] or 0)
57 | green = int(values.get('green', [''])[0] or 0)
58 | blue = int(values.get('blue', [''])[0] or 0)
59 | opacity = int(values.get('opacity', [''])[0] or 0)
60 |
61 | # Now these expressions have become unreadable and repetitive.
62 | # Here's where a helper function would be useful:
63 |
64 | def get_value(values, key, default=0):
65 | result = values.get(key, [''])
66 | if result[0]:
67 | result = int(result[0])
68 | else:
69 | result = default
70 | return result
71 |
72 | red = get_value(values, 'red')
73 | green = get_value(values, 'green')
74 | blue = get_value(values, 'blue')
75 | opacity = get_value(values, 'opacity')
76 |
77 | # Though it means more lines of code, in the end its more readable.
78 |
--------------------------------------------------------------------------------
/import_modules.py:
--------------------------------------------------------------------------------
1 | '''Importing Modules'''
2 |
3 |
4 | # You can import your own python file as a module or a module from the
5 | # python standard library in the same way:
6 |
7 | import random
8 | import myfile
9 |
10 | # when you import this way, you need to include the module name as a prefix
11 | # to any functions you want to use from that module. This is to avoid any
12 | # possible naming conflicts between modules.
13 |
14 | possibilities = ['red', 'orange', 'yellow', 'green', 'blue', 'cyan']
15 |
16 | random.choice(possibilities)
17 |
18 | # Import a function from a module:
19 |
20 | from random import choice
21 |
22 | # when you import this way, you can reference the function name directly:
23 |
24 | choice(possibilities)
25 |
26 | # Import a module and give it another name using 'as':
27 |
28 | import random as ran
29 |
30 | ran.choice(possibilities)
31 |
32 | # Import a function from a module and give it another name:
33 |
34 | from random import choice as mix
35 |
36 | mix(possibilities)
37 |
38 | # Import a class from a module:
39 |
40 | from myclasses import Person
41 |
42 | # When importing, Python looks in the current directory first (so if you have a
43 | # file named random.py in your current directory, it will use that over the one
44 | # in the standard library. The standard library on a mac:
45 |
46 | # Library/Frameworks/Python.framework/Versions/3.5/lib/python3.6
47 |
48 |
49 | # import ordering
50 | # -----------------------------------------------------------------------------
51 | # According to PEP8, imports should be listed in the following order.
52 | # Some also put a space between each group and some separate the regular
53 | # import statements from the 'from' import statements. Up to you.
54 |
55 | # 1. Standard library imports
56 | # 2. Third-party imports
57 | # 3. Applications imports
58 |
59 |
60 | # __name__ == '__main__'
61 | # -----------------------------------------------------------------------------
62 | # If you intend for your module to be imported, remember that your program
63 | # should most likely run by calling a function, not just start running as soon
64 | # as its imported. When you want to test and run your code from within module,
65 | # itself use this:
66 |
67 | if __name__ == '__main__':
68 | pass # call the function that starts the script
69 |
70 |
71 | # see also packages.py
72 |
--------------------------------------------------------------------------------
/iterables_summary.py:
--------------------------------------------------------------------------------
1 | '''Review of Lists, Tuples, Dictionaries & Sets'''
2 |
3 |
4 | # Compare data structures
5 | # -----------------------------------------------------------------------------
6 | # List: mutable, ordered, values don't need to be unique
7 | colours_list = ['red', 'orange', 'black', 'black']
8 |
9 | # Tuple: immutable, ordered, values don't need to be unique
10 | colours_tuple = ('red', 'orange', 'black', 'black')
11 |
12 | # Sets: mutable, unordered, values must be unique
13 | colours_set = {'red', 'orange', 'black'}
14 |
15 | # Frozensets : immutable, unordered, values must be unique
16 | colours_fset = frozenset(('red', 'orange', 'black'))
17 |
18 | # Dict keys: immutable, ordered (as of Python 3.6), values must be unique
19 | # Dict values: mutable, ordered (as of Python 3.6), values don't need to be unique
20 | colours_dict = {
21 | 'red': 'Pantone 185C',
22 | 'orange': 'Pantone 021C',
23 | 'black': 'Pantone 6C'
24 | }
25 |
26 | print(type(colours_list)) #
27 | print(type(colours_tuple)) #
28 | print(type(colours_set)) #
29 | print(type(colours_fset)) #
30 | print(type(colours_dict)) #
31 |
32 | # In each case use [] brackets to access a single element
33 | # (except sets which don't support indexing):
34 |
35 | print(colours_list[2]) # black
36 | print(colours_tuple[2]) # black
37 | print(colours_dict['black']) # Pantone 6C
38 |
39 | # You can combine data structures, for example, you can make:
40 | # - a tuple of lists
41 | # - a list of lists
42 | # - a dictionary of lists (only the values van be lists)
43 |
44 | colors = ['magenta', 'red', 'cyan']
45 | moods = ['happy', 'sad', 'confused']
46 | senses = ['smell', 'touch', 'taste']
47 |
48 | dict_of_lists = {
49 | 'Colors': colors,
50 | 'Moods': moods,
51 | 'Senses': senses
52 | }
53 |
54 | # Reminder: Dictionary keys are immutable, therefor you cannot use a list
55 | # or another dictionary as a key, but you CAN use a tuple or a frozenset
56 | # because those are immutable too. A good example of this is with mapping –
57 | # the GPS coordinates may be the key:
58 |
59 | places = {
60 | (44, -93, 344): 'home',
61 | (27, -80, 200): 'work'
62 | }
63 |
64 | # Note that these aren't the only iterables in Python. Other iterables include:
65 | # - strings
66 | # - generators
67 | # - pandas series objects
68 |
--------------------------------------------------------------------------------
/iterating_with_for.py:
--------------------------------------------------------------------------------
1 | '''Iterating with for'''
2 |
3 |
4 | # Iterating over lists, tuples and sets returns individual items:
5 | # -----------------------------------------------------------------------------
6 |
7 | list1 = ['one', 'two', 'three']
8 | tuple1 = ('four', 'five', 'six')
9 | set1 = {'seven', 'eight', 'nine'}
10 |
11 | for item in list1:
12 | print(item)
13 | # one
14 | # two
15 | # three
16 |
17 | for item in tuple1:
18 | print(item)
19 | # four
20 | # five
21 | # six
22 |
23 | for item in set1:
24 | print(item)
25 | # eight
26 | # nine
27 | # seven
28 |
29 | # You cab also iterate over a slice.
30 | for item in list1[2:]:
31 | print(item)
32 | # three
33 |
34 |
35 | # Iterating over strings returns characters
36 | # -----------------------------------------------------------------------------
37 |
38 | string1 = "ten"
39 |
40 | for char in string1:
41 | print(char)
42 | # t
43 | # e
44 | # n
45 |
46 |
47 | # Iterating over dictionaries
48 | # -----------------------------------------------------------------------------
49 |
50 | dict1 = {'eleven': '11', 'twelve': '12', 'thirteen': '13'}
51 |
52 | for item in dict1: # will choose keys
53 | print(item)
54 | # eleven
55 | # twelve
56 | # thirteen
57 |
58 | for item in dict1.keys(): # works the same as above
59 | print(item)
60 | # eleven
61 | # twelve
62 | # thirteen
63 |
64 | # Therefor, to iterate over a dictionary and get values:
65 | for item in dict1.values():
66 | print(item)
67 | # 11
68 | # 12
69 | # 13
70 |
71 | # To iterate over both keys and values:
72 | for item in dict1.items():
73 | print(item)
74 | # ('eleven', '11')
75 | # ('twelve', '12')
76 | # ('thirteen', '13')
77 |
78 | # Break apart the resulting tuple by doing this:
79 | for key, value in dict1.items():
80 | print(key, '–', value)
81 | # eleven – 11
82 | # twelve – 12
83 | # thirteen – 13
84 |
85 |
86 | # Iterating over multiple sequences with zip()
87 | # -----------------------------------------------------------------------------
88 |
89 | days = ['Monday', 'Tuesday', 'Wednesday']
90 | fruits = ['Apple', 'Banana', 'Pear']
91 | drinks = ['Tea', 'Juice', 'Wine']
92 | desserts = ['Ice cream', 'Cookies', 'Cake', 'Candy']
93 |
94 | for day, fruit, drink, dessert in zip(days, fruits, drinks, desserts):
95 | print(day.upper())
96 | print('–', fruit)
97 | print('–', drink)
98 | print('–', dessert)
99 |
100 |
101 | # Using range(start, stop, step)
102 | # -----------------------------------------------------------------------------
103 |
104 | for x in range(5, -1, -1):
105 | print(x, end='...') # 5...4...3...2...1...0..
106 |
107 |
108 | # using multiple for loops
109 | # -----------------------------------------------------------------------------
110 |
111 | for i in range(1, 13):
112 | for j in range(1, 13):
113 | print(i, 'x', j, '=', i * j)
114 | print('------------------')
115 |
116 |
117 | # break and continue
118 | # -----------------------------------------------------------------------------
119 | # break is useful when you want to terminate a loop early if some condition
120 | # is met. Continue skips past to the next iteration.
121 |
122 | cheeses = ['brie', 'cheddar', 'feta', 'gorgonzola']
123 |
124 | for cheese in cheeses:
125 | if cheese == 'feta':
126 | break
127 | print('We have', cheese)
128 |
129 | # We have brie
130 | # We have cheddar
131 |
132 | for cheese in cheeses:
133 | if cheese == 'feta':
134 | continue
135 | print('We have', cheese)
136 |
137 | # We have brie
138 | # We have cheddar
139 | # We have gorgonzola
140 |
141 |
142 | # Create your own iterator with iter() and next()
143 | # -----------------------------------------------------------------------------
144 | # A for loop actually creates an iterator object that will return each
145 | # item that it's iterating over. When there are no more items, the iterator
146 | # returns an error. The for loop is built to handle the error and terminates.
147 |
148 | string = '123'
149 | my_iterator = iter(string)
150 | print(my_iterator) #
151 | print(next(my_iterator)) # 1
152 | print(next(my_iterator)) # 2
153 | print(next(my_iterator)) # 3
154 |
155 | # To confirm, the following two are the same thing, we don't need to explicitly
156 | # add the iter() as the for loop will do it for us:
157 |
158 | for char in string:
159 | print(char, end='...') # 1...2...3...
160 |
161 | for char in iter(string):
162 | print(char, end='...') # 1...2...3...
163 |
164 |
165 | # Important Note:
166 | # -----------------------------------------------------------------------------
167 | # A for loop is effective for iterating through a list but apparently, "You
168 | # shouldn't modify a list inside a for loop because Python will have trouble
169 | # keeping track of the items in the list. To modify a list as you work through
170 | # it, use a while loop." Using a while loop allows you to better collect,
171 | # store and organize.
172 |
--------------------------------------------------------------------------------
/json_example.py:
--------------------------------------------------------------------------------
1 | '''JSON Example'''
2 |
3 |
4 | # see also structured_file_formats.py
5 |
6 | # The JSON (JavaScript Object Notation) module allows you to dump simple python
7 | # data structures into a file and load it back in next time the programs runs.
8 | # You can also use JSON to share data between different python programs or
9 | # other programming languages. It's a useful, portable, easy-to-learn file
10 | # format. The pythons data types it can store are: strings, numbers, booleans,
11 | # lists and dictionaries with string keys.
12 |
13 | # There are two sets of functions for working with JSON:
14 |
15 | # json.dump() and json.load() – for storing and retrieving JSON from a file
16 | # json.dumps() and json.loads() – for creating and parsing JSON strings
17 |
18 |
19 | # JSON to file
20 | # -----------------------------------------------------------------------------
21 |
22 | import json
23 |
24 | # The json.dump() function takes two arguments: a piece of data to store and
25 | # the file object to store the data in.
26 |
27 | numbers = [4, 5, 7, 9, 11, 13]
28 | username = input("What is your name? ")
29 | filename = 'data/numbers.json'
30 |
31 | with open(filename, 'w') as fob:
32 | json.dump((numbers, username), fob)
33 |
34 | # Read the data back in with json.load():
35 |
36 | with open(filename) as fob:
37 | data = json.load(fob)
38 |
39 | print(type(data)) #
40 |
41 | numbers2, username2 = data
42 |
43 | print(type(numbers2)) #
44 | print(type(username2)) #
45 | print('Hello', username2) # Hello Raja
46 | print(numbers2) # [4, 5, 7, 9, 11, 13]
47 |
48 |
49 | # JSON to strings
50 | # -----------------------------------------------------------------------------
51 | # JSON strings work well for when you want to share data structures between
52 | # programs and languages (e.g. python dictionary to Javscript).
53 |
54 | data = {
55 | 'date': '2019-04-10',
56 | 'count': 6,
57 | 'session_id': 102
58 | }
59 |
60 | # create a JSON string with json.dumps():
61 |
62 | data_json = json.dumps(data)
63 |
64 | print(type(data_json), data_json)
65 | # {"date": "2019-04-10", "count": 6, "session_id": 102}
66 |
67 | # parse a JSON string into a python data structure with json.loads():
68 |
69 | json_string = '["hello", 100, [2019, 4, 10]]'
70 |
71 | data = json.loads(json_string)
72 |
73 | print(type(data), data)
74 | # ['hello', 100, [2019, 4, 10]]
75 |
76 |
77 | # Encoders and Decoders (json.JSONDecoder, json.JSONEncoder)
78 | # -----------------------------------------------------------------------------
79 | # When you convert from Python to JSON, Python objects are encoded to the
80 | # following JavaScript equivalents:
81 |
82 | # Python JSON
83 | # ------ ------
84 | # dict Object
85 | # list Array
86 | # tuple Array
87 | # str String
88 | # int Number
89 | # float Number
90 | # True true
91 | # False false
92 | # None null
93 |
94 |
95 | # Extending the JSONEncoder
96 | # -----------------------------------------------------------------------------
97 | # see structured_file_formats.py
98 |
--------------------------------------------------------------------------------
/jupyter_notebook.md:
--------------------------------------------------------------------------------
1 | # Jupyter Notebook
2 |
3 |
4 | Jupyter Notebook is a hybrid editor and interactive shell that runs in the browser. It works really well for exploring large sets of data. It does not replace your regular editor or IDE (which is more useful for working with multiple files and projects) but definitely worth considering if you need to explore your datasets and test your code before implementing.
5 |
6 | ```
7 | $ pip install jupyter
8 | ```
9 |
10 | If you intend on working with excel files, you should also install:
11 |
12 | ```
13 | $ pip install xlrd
14 | ```
15 |
16 | Once installed, start a jupyter session by navigating to your working directory in the command line, then launch:
17 |
18 | ```
19 | $ jupyter notebook
20 | ```
21 |
22 | This will launch a jupyter session in a new browser window. You will see all your files listed from your current working directory.
23 |
24 | From the dropdown in the top right corner, choose to create a new python notebook. Python is listed as the only type of notebook because we installed jupyter via python with pip. This opens a new untitled tab. When you give it a name and you'll see a new .ipynb file and folder show up in your working directory. The .ipynb file allows you to return to your previous saved session (follow the same steps to launch jupyter, but instead of creating a new session, select the .ipynb file).
25 |
26 | The editable field here is the shell. You can enter in as many lines of code as you want. Hitting the return key will not execute the code. When you are ready to execute hit `ctrl + return`.
27 |
28 | At this point you can continue to edit the code in the first shell 'cell', or you can create a new 'cell' by hitting `option/alt + return`. You can execute your code and immediately create a new 'cell' with `shift + return`.
29 |
30 | - To remove a 'cell', press `esc`, then `dd`
31 | - To add a cell without executing press `esc`, then `b`
32 |
33 | You can find more shortcuts under the help menu.
34 |
35 | To view data try this; in a new jupyter 'cell':
36 | ```python
37 | import pandas
38 | ```
39 |
40 | In a second cell:
41 | ```python
42 | df = pandas.read_csv('data/supermarkets.csv')
43 | df
44 | ```
45 |
46 | When you execute the second cell, you should see the data displayed in a friendly, easy-to-read table. Note the header rows in CSV files are shown in bold text. Try setting the header arg to None to see the difference:
47 |
48 | ```python
49 | df1 = pandas.read_csv('data/supermarkets.csv', header=None)
50 | ```
51 |
52 | Another nice feature of jupyter is the ability to get help on methods or classes by typing a question mark:
53 | ```python
54 | df.set_index?
55 | ```
56 |
57 | This will open a window with detailed help... really nice.
58 |
59 | When you are finished working, logout of the browser windows. Back in the command line window, `CTRL-c`, then enter `y` to quit:
60 | ```
61 | The Jupyter Notebook is running at:
62 | http://localhost:8888/?token=d1ac3...
63 | Shutdown this notebook server (y/[n])? y
64 | [C 10:16:08.918 NotebookApp] Shutdown confirmed
65 | ```
66 |
--------------------------------------------------------------------------------
/keywords.py:
--------------------------------------------------------------------------------
1 | '''Python Keywords'''
2 |
3 |
4 | # The following identifiers are used as reserved words, or keywords of the
5 | # language, and cannot be used as ordinary identifiers. If you absolutely
6 | # feel for clarity that you must use one of these names for your own variable,
7 | # an accepted format to follow the name with an underscore. For example: from_
8 |
9 | import keyword
10 |
11 | for word in keyword.kwlist:
12 | print(word)
13 |
14 | # False
15 | # None
16 | # True
17 | # and
18 | # as
19 | # assert
20 | # async
21 | # await
22 | # break
23 | # class
24 | # continue
25 | # def
26 | # del
27 | # elif
28 | # else
29 | # except
30 | # finally
31 | # for
32 | # from
33 | # global
34 | # if
35 | # import
36 | # in
37 | # is
38 | # lambda
39 | # nonlocal
40 | # not
41 | # or
42 | # pass
43 | # raise
44 | # return
45 | # try
46 | # while
47 | # with
48 | # yield
49 |
--------------------------------------------------------------------------------
/logging_errors.py:
--------------------------------------------------------------------------------
1 | '''Logging Error Messages'''
2 |
3 |
4 | # The Python standard library module for logging is logging.
5 | # https://docs.python.org/3/library/logging.html
6 |
7 | # The logging module includes:
8 | # – The message that you want to save to the log
9 | # – Ranked priority levels as functions:
10 | # debug(), info(), warning(), error(), and critical()
11 | # – One or more logger objects as the main connection with the module
12 | # – Handlers that direct the message to your terminal, a file, a database,
13 | # or somewhere else
14 | # – Formatters that create the output
15 | # – Filters that make decisions based on the input
16 |
17 | import logging
18 |
19 | fmt = '%(asctime)s %(levelname)s %(lineno)s %(message)s'
20 | logging.basicConfig(level=logging.DEBUG, filename='data/test.log', format=fmt)
21 |
22 | # priority levels:
23 | logging.debug('debug message')
24 | logging.info('info message')
25 | logging.warning('warning message')
26 | logging.error('error message')
27 | logging.critical('critical message')
28 |
29 |
30 | # Breakdown
31 | # -----------------------------------------------------------------------------
32 | # The default priority level is warn. Set the default by using basicConfig().
33 | # This config should appear before any other logging functions as above.
34 |
35 | logging.basicConfig(level=logging.DEBUG)
36 |
37 | # handlers direct messages to different places, for example, a log file:
38 |
39 | logging.basicConfig(level=logging.DEBUG, filename='data/test.log')
40 |
41 | # you can format your logged messages:
42 |
43 | fmt = '%(asctime)s %(levelname)s %(lineno)s %(message)s'
44 | logging.basicConfig(level=logging.DEBUG, filename='data/test.log', format=fmt)
45 |
46 | # here's a logger object:
47 |
48 | logger = logging.getLogger('MyLogger')
49 | logger.debug('here is my debug message')
50 |
51 | # Calling basicConfig() with a filename argument created a FileHandler and made
52 | # it available to the logger. The logging module includes at least 15 handlers
53 | # to send messages to places such as the screen, email, web servers and files.
54 |
55 | # The information here is pretty scant. For more information on this topic, go
56 | # through the following in Doug Hellman's Python 3 Standard Library by example:
57 | # p.980–986, p.563–564, p.644–647, p.650–653, p.671–674
58 |
59 |
60 | # Log Record attributes
61 | # -----------------------------------------------------------------------------
62 | # There are a number of attributes (bits of information) that can be included
63 | # in your logged message format. For a full list see:
64 | # https://docs.python.org/3/library/logging.html#logrecord-attributes
65 |
66 |
67 | # Logging Levels
68 | # -----------------------------------------------------------------------------
69 | # The predifined logging levels all have a numeric value associated to them.
70 | # This is mostly of interest because you can define your own levels.
71 |
72 | # Level | Numeric value
73 | # ----------|--------------
74 | # CRITICAL | 50
75 | # ERROR | 40
76 | # WARNING | 30
77 | # INFO | 20
78 | # DEBUG | 10
79 | # NOTSET | 0
80 |
81 | # To define your own level:
82 |
83 | SPECIAL_INFO_LEVEL_NUM = 21
84 | logging.addLevelName(SPECIAL_INFO_LEVEL_NUM, 'SPECIAL_INFO')
85 |
86 | def special_info(self, message, *args, **kws):
87 | if self.isEnabledFor(SPECIAL_INFO_LEVEL_NUM):
88 | self._log(SPECIAL_INFO_LEVEL_NUM, message, args, **kws)
89 |
90 | logging.Logger.special_info = special_info
91 |
92 | logger.special_info('Hey, this is special')
93 |
94 | # That being said, while defining your own levels is possible, it shouldn't
95 | # really be necessary, as the existing levels have been chosen on the basis of
96 | # practical experience. It's also a very bad idea if you are developing a
97 | # library as your custom level could conflict with others.
98 |
--------------------------------------------------------------------------------
/match_statements.py:
--------------------------------------------------------------------------------
1 | '''Match Statements'''
2 |
3 |
4 | # New to Python 3.10, structural pattern matching has been added in the form of
5 | # a match statement and case statements of patterns with associated actions. It
6 | # seems similar to JavaScript switch statements but better.
7 |
8 | # https://peps.python.org/pep-0634/
9 | # https://peps.python.org/pep-0636/
10 |
11 | # Patterns consist of sequences, mappings, primitive data types as well as class
12 | # instances. Pattern matching enables programs to extract information from
13 | # complex data types, branch on the structure of data, and apply specific
14 | # actions based on different forms of data.
15 |
16 | subject = 'b'
17 | result = None
18 |
19 | match subject:
20 | case 'a':
21 | result = 'one'
22 | case 'b':
23 | result = 'two'
24 | case 'c':
25 | result = 'three'
26 | case _:
27 | result = 'wildcard'
28 |
29 | print(result) # two
30 |
31 | # A match statement takes an expression and compares its value to successive
32 | # patterns given as one or more case blocks. Specifically, pattern matching
33 | # operates by:
34 |
35 | # - using data with type and shape (the subject)
36 | # - evaluating the subject in the match statement
37 | # - comparing the subject with each pattern in a case statement from top to
38 | # bottom until a match is confirmed.
39 | # - executing the action associated with the pattern of the confirmed match
40 | # - If an exact match is not confirmed, the last case, a wildcard _, if provided,
41 | # will be used as the matching case. If an exact match is not confirmed and a
42 | # wildcard case does not exist, the entire match block is a no-op.
43 |
44 |
45 | # Match to a literal
46 | # -----------------------------------------------------------------------------
47 |
48 | def http_status(code):
49 | match code:
50 | case 200:
51 | return 'ok'
52 | case 400:
53 | return 'bad request'
54 | case 401 | 403 | 405:
55 | return 'not allowed'
56 | case 404:
57 | return 'not found'
58 | case _:
59 | return 'something else broke'
60 |
61 | print(http_status(500)) # something else broke
62 |
63 |
64 | # Patterns with a variable
65 | # ----------------------------------------------------------------------------
66 |
67 | def show_point(point):
68 | match point:
69 | case (0, 0):
70 | print('origin')
71 | case (x, 0):
72 | print(f'x={x}')
73 | case (0, y):
74 | print(f'y={y}')
75 | case (x, y):
76 | print(f'x={x}, y={y}')
77 | case _:
78 | raise ValueError('Not a point')
79 |
80 | show_point((15, 4)) # x=15, y=4
81 | show_point((0, 5)) # y=5
82 |
83 |
84 | # Patterns with classes
85 | # ----------------------------------------------------------------------------
86 |
87 | class Point:
88 | def __init__(self, x, y):
89 | self.x = x
90 | self.y = y
91 |
92 | def location(point):
93 | match point:
94 | case Point(x=0, y=0):
95 | print('origin')
96 | case Point(x=x, y=y):
97 | print(f'x={x}, y={y}')
98 | case _:
99 | raise ValueError('Not a point')
100 |
101 |
102 | location(Point(x=0, y=0)) # origin
103 | location(Point(x=12, y=66)) # x=12, y=66
104 |
105 |
106 | # Add an if clause as a 'guard'
107 | # ----------------------------------------------------------------------------
108 |
109 | def location(point):
110 | match point:
111 | case Point(x=0, y=0):
112 | print('origin')
113 | case Point(x=x, y=y) if x == y:
114 | print(f'the point is on the diagonal: x={x}, y={y}')
115 | case Point(x=x, y=y):
116 | print(f'x={x}, y={y}')
117 | case _:
118 | raise ValueError('Not a point')
119 |
120 |
121 | location(Point(x=12, y=12)) # the point is on the diagonal: x=12, y=12
122 |
123 |
124 | # Complex patterns and the wildcard
125 | # ----------------------------------------------------------------------------
126 | # The _ wildcard can be used for items within a pattern, for example:
127 |
128 | message = ('error', 100, ['foo'])
129 |
130 | match message:
131 | case ('warning', code, 50):
132 | print('a warning has been received')
133 | case ('error', code, _):
134 | print(f'an error {code} has occurred')
135 |
136 | # an error 100 has occurred
137 |
138 |
--------------------------------------------------------------------------------
/matplotlib_csv_example.py:
--------------------------------------------------------------------------------
1 | '''Matplotlib – Weather Data'''
2 |
3 |
4 | # The weather data for this example was originally obtained from:
5 | # https://www.wunderground.com/history/
6 | # Some other good data sources for historical weather data:
7 | # https://www.ncdc.noaa.gov/data-access/quick-links
8 | # http://climate.weather.gc.ca/index_e.html
9 |
10 | import csv
11 | from datetime import datetime
12 | from matplotlib import pyplot as plt
13 |
14 |
15 | filename = 'data/death_valley_2014.csv'
16 | placename = 'Death Valley, CA'
17 |
18 |
19 | # Exploring the data:
20 | # -----------------------------------------------------------------------------
21 |
22 | with open(filename) as fob:
23 | reader = csv.reader(fob)
24 | header_row = next(reader)
25 | for index, column_header in enumerate(header_row):
26 | print(index, column_header)
27 | # 0 PST
28 | # 1 Max TemperatureF
29 | # 2 Mean TemperatureF
30 | # 3 Min TemperatureF
31 | # 4 Max Dew PointF
32 | # 5 MeanDew PointF
33 | # 6 Min DewpointF
34 | # 7 Max Humidity
35 | # 8 Mean Humidity
36 | # 9 Min Humidity
37 | # 10 Max Sea Level PressureIn
38 | # 11 Mean Sea Level PressureIn
39 | # 12 Min Sea Level PressureIn
40 | # 13 Max VisibilityMiles
41 | # 14 Mean VisibilityMiles
42 | # 15 Min VisibilityMiles
43 | # 16 Max Wind SpeedMPH
44 | # 17 Mean Wind SpeedMPH
45 | # 18 Max Gust SpeedMPH
46 | # 19 PrecipitationIn
47 | # 20 CloudCover
48 | # 21 Events
49 | # 22 WindDirDegrees
50 |
51 |
52 | # Extracting and reading data:
53 | # -----------------------------------------------------------------------------
54 |
55 | with open(filename) as fob:
56 | reader = csv.reader(fob)
57 | header_row = next(reader)
58 | dates, highs, lows = [], [], []
59 | for row in reader:
60 | try:
61 | current_date = datetime.strptime(row[0], '%Y-%m-%d')
62 | high = int(row[1])
63 | low = int(row[3])
64 | except ValueError:
65 | print(current_date, 'missing data')
66 | else:
67 | dates.append(current_date)
68 | highs.append(high)
69 | lows.append(low)
70 |
71 |
72 | # Plotting the data:
73 | # -----------------------------------------------------------------------------
74 |
75 | # creates a figure and one subplot
76 | fig, ax = plt.subplots(figsize=(10, 5))
77 |
78 | # plot the data:
79 | plt.plot(dates, highs, c='tomato', alpha=0.6)
80 | plt.plot(dates, lows, c='darkturquoise', alpha=0.6)
81 |
82 | # format the plot:
83 | plt.fill_between(dates, highs, lows, facecolor='papayawhip', alpha=0.6)
84 | title = 'Daily high and low temperatures, 2014\n{}'.format(placename)
85 | plt.title(title, fontsize=10)
86 | plt.xlabel('', fontsize=9)
87 | fig.autofmt_xdate()
88 | plt.xticks(rotation=25)
89 | plt.ylabel('Termperature (F)', fontsize=9, fontweight='bold')
90 | plt.tick_params(axis='both', which='major', labelsize=7)
91 |
92 | # tells x, y axis to use this range
93 | # plt.axis([datetime(2014, 1, 1), datetime(2014, 12, 1), 0, 120])
94 | # if you just want to set one axis:
95 | ax.set_xlim([datetime(2014, 1, 1), datetime(2014, 12, 1)])
96 | # ax.set_ylim([20, 120])
97 |
98 | # display the plot:
99 | plt.show()
100 |
--------------------------------------------------------------------------------
/matplotlib_example.py:
--------------------------------------------------------------------------------
1 | '''Matplotlib – Random Walk'''
2 |
3 |
4 | # A random walk is a path that has no clear direction but is determined by a
5 | # series of random decisions. For example, a grain of pollen floating on a drop
6 | # of water moves across the surface in a random walk. It is pushed around by
7 | # water molecules and molecular motion in a water drop happens to be random.
8 |
9 | # See also: matplotlib_example.py
10 |
11 | # This example uses the matplotlib.pyplot.scatter plot:
12 | # https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html?highlight=scatter#matplotlib.pyplot.scatter
13 |
14 |
15 | # Ideally the following class would be saved as a module: random_walk.py
16 | # -----------------------------------------------------------------------------
17 |
18 | from random import choice
19 |
20 | class RandomWalk():
21 | '''A class to generate random walks.'''
22 |
23 | def __init__(self, num_points=5000):
24 | '''Initialize attributes of walk.'''
25 | self.num_points = num_points
26 |
27 | # all walks start at (0,0):
28 | self.x_values = [0]
29 | self.y_values = [0]
30 |
31 | def fill_walk(self):
32 | '''Calculate all the points in the walk.'''
33 | # keep tracking the steps until the walk reaches the desired length:
34 | while len(self.x_values) < self.num_points:
35 | # decide on which direction to go and how far to go:
36 | x_direction = choice([1, -1])
37 | x_distance = choice([0, 1, 2, 3, 4])
38 | x_step = x_direction * x_distance
39 |
40 | y_direction = choice([1, -1])
41 | y_distance = choice([0, 1, 2, 3, 4])
42 | y_step = y_direction * y_distance
43 | # reject moves that go nowhere:
44 | if x_step == 0 and y_step == 0:
45 | continue
46 | # calculate the next x and y values:
47 | next_x = self.x_values[-1] + x_step
48 | next_y = self.y_values[-1] + y_step
49 |
50 | self.x_values.append(next_x)
51 | self.y_values.append(next_y)
52 |
53 |
54 | # Ideally the following would be in it's own file and we'd import the class
55 | # -----------------------------------------------------------------------------
56 |
57 | import matplotlib.pyplot as plt
58 | from matplotlib.colors import LinearSegmentedColormap
59 | # from random_walk import RandomWalk
60 |
61 | # colours:
62 | a = '#69F4BD'
63 | b = '#319589'
64 | c = '#344D6c'
65 | d = '#372560'
66 | e = '#3E1B3C'
67 |
68 | rw1 = RandomWalk(50000)
69 | rw1.fill_walk()
70 |
71 | # optional setting the window size:
72 | plt.figure(figsize=(9, 5))
73 |
74 | # make your own colour map:
75 | cmap = LinearSegmentedColormap.from_list('mycmap', [a, b, c, d, e])
76 |
77 | # create a list for the range needed for the colour map:
78 | point_numbers = list(range(rw1.num_points))
79 |
80 | # the main plot:
81 | plt.scatter(rw1.x_values, rw1.y_values, s=1, c=point_numbers, cmap=cmap)
82 |
83 | # emphasize the start and end points:
84 | plt.scatter(0, 0, c='gold', s=25)
85 | plt.scatter(rw1.x_values[-1], rw1.y_values[-1], c='red', s=25)
86 |
87 | # title and axis size:
88 | plt.title('Random Walk', fontsize=9)
89 | plt.tick_params(axis='both', which='major', labelsize=7)
90 |
91 | plt.show()
92 |
--------------------------------------------------------------------------------
/namespaces.py:
--------------------------------------------------------------------------------
1 | '''Namespaces'''
2 |
3 |
4 | # Local and global variables
5 | # -----------------------------------------------------------------------------
6 | # You can get the value of a global variable from within a function
7 |
8 | animal = 'fruitbat'
9 |
10 | def print_global():
11 | print('inside print_global:', animal)
12 |
13 | print_global()
14 | # inside print_global: fruitbat
15 |
16 | # But if you get the value of a global variable and and try to change it within
17 | # a function, you get an error because as soon as you start assigning to a
18 | # variable, python wants to make it a local variable, and since no local
19 | # variable has been initialized... error:
20 |
21 | def change_and_print_global():
22 | print('inside change_and_print_global:', animal)
23 | animal = 'wombat'
24 | print('after the change:', animal)
25 |
26 | # change_and_print_global()
27 | # UnboundLocalError: local variable 'animal' referenced before assignment
28 |
29 | # So, if you reassign the variable you are actually making a new local variable
30 | # (also named animal) inside of the function. Use ID to see they're different:
31 |
32 | def change_local():
33 | animal = 'wombat'
34 | print('local animal:', animal, id(animal))
35 |
36 | change_local()
37 | print('global animal:', animal, id(animal))
38 | # local animal: wombat 4316476056
39 | # global animal: fruitbat 4316756144
40 |
41 | # To access and change a global variable from within a function you need to be
42 | # explicit by using the global keyword:
43 |
44 | def change_and_print_global():
45 | global animal
46 | print('inside change_and_print_global:', animal)
47 | animal = 'wombat'
48 | print('after the change:', animal)
49 |
50 | change_and_print_global()
51 | # inside change_and_print_global: fruitbat
52 | # after the change: wombat
53 |
54 | print(f'global animal: {animal}')
55 | # global animal: wombat
56 |
57 |
58 | # nonlocal
59 | # -----------------------------------------------------------------------------
60 | # Python 3 introduced the nonlocal keyword that allows you to assign to
61 | # variables in an outer, but non-global, scope.
62 |
63 | x = 'orange'
64 |
65 | def testing_nonlocal():
66 | x = 'lemon'
67 | def inside():
68 | nonlocal x # if this statement is removed, the printed output
69 | x = 'lime' # would be 'lime', then 'lemon' because we would
70 | print(x) # have 3 unique 'x' variables.
71 | inside()
72 | print(x)
73 |
74 | print(x)
75 | testing_nonlocal()
76 | # orange
77 | # lime
78 | # lime
79 |
80 | # NOTE: when you reference a variable name, python will start by looking for
81 | # the variable definition locally, and then move outward until if finds it.
82 | # The order of scopes is as follows:
83 |
84 | # – local
85 | # – enclosing
86 | # – global
87 | # – built-ins
88 |
89 |
90 | # locals() and globals()
91 | # -----------------------------------------------------------------------------
92 | # Python provides two functions to access the contents of your Namespaces
93 | # locals() and globals():
94 |
95 | fruit = 'orange'
96 |
97 | def testing_local():
98 | fruit = 'apple'
99 | print('locals:', locals())
100 |
101 | testing_local()
102 | # locals: {'fruit': 'apple'}
103 |
104 | print('globals:')
105 | g = sorted(globals())
106 | for i in g:
107 | print(i)
108 | # globals:
109 | # __annotations__
110 | # __builtins__
111 | # __cached__
112 | # __doc__
113 | # __file__
114 | # __loader__
115 | # __name__
116 | # __package__
117 | # __spec__
118 | # animal
119 | # change_and_print_global
120 | # change_local
121 | # fruit
122 | # print_global
123 | # testing_local
124 | # testing_nonlocal
125 | # x
126 |
127 |
128 | # __name__, __doc__
129 | # -----------------------------------------------------------------------------
130 | # The name of a function is in the system variable: function.__name__
131 | # The functions document string in in the variable: function.__doc__
132 |
133 | def amazing():
134 | '''This is the functions description'''
135 | print('This function is named:', amazing.__name__)
136 | print('Its docstring says:', amazing.__doc__)
137 | print('The main program running is assigned a special name:', __name__)
138 |
139 | amazing()
140 | # This function is named: amazing
141 | # Its docstring says: This is the functions description
142 | # The main program running is assigned a special name: __main__
143 |
--------------------------------------------------------------------------------
/numpy_modules.py:
--------------------------------------------------------------------------------
1 | '''A brief look at NumPy (Numerical Python).'''
2 |
3 |
4 | # http://www.numpy.org/
5 |
6 | # NumPy is a library for Python that adds support for "large, multi-dimensional
7 | # arrays and matrices, along with a large collection of high-level mathematical
8 | # functions to operate on these arrays."
9 |
10 | # numpy arrays look similar to python lists but they are much more efficient,
11 | # especially when it comes to iterating over them, running other functions.
12 |
13 | # numpy is a base library for many other libraries such as pandas, matplotlib,
14 | # and OpenCV (image processing library).
15 |
16 | import numpy
17 |
18 |
19 | # One Dimensional Arrays
20 | # -----------------------------------------------------------------------------
21 | n = numpy.arange(27)
22 |
23 | print(n) # [ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...]
24 | print(type(n)) #
25 |
26 | n_start_stop_step = numpy.arange(0, 100, 10)
27 | print(n_start_stop_step) # [ 0 10 20 30 40 50 60 70 80 90]
28 |
29 |
30 | # Two Dimensional Arrays
31 | # -----------------------------------------------------------------------------
32 | n = n.reshape(3, 9)
33 |
34 | print(n)
35 | # [[ 0 1 2 3 4 5 6 7 8]
36 | # [ 9 10 11 12 13 14 15 16 17]
37 | # [18 19 20 21 22 23 24 25 26]]
38 |
39 | # This is how image files can be stored... each row is a row of pixels.
40 |
41 |
42 | # Three Dimensional Arrays
43 | # -----------------------------------------------------------------------------
44 | n = n.reshape(3, 3, 3)
45 |
46 | print(n)
47 | # [[[ 0 1 2]
48 | # [ 3 4 5]
49 | # [ 6 7 8]]
50 | #
51 | # [[ 9 10 11]
52 | # [12 13 14]
53 | # [15 16 17]]
54 | #
55 | # [[18 19 20]
56 | # [21 22 23]
57 | # [24 25 26]]]
58 |
59 |
60 | # Create numpy arrays from Python lists
61 | # -----------------------------------------------------------------------------
62 |
63 | a = [12, 45, 255]
64 | b = [34, 45, 101]
65 | c = [122, 60, 10]
66 |
67 | n = numpy.asarray([a, b, c])
68 |
69 | print(type(n)) #
70 | print(n)
71 | # [[ 12 45 255]
72 | # [ 34 45 101]
73 | # [122 60 10]]
74 |
75 |
76 | # Indexing, slicing, iterating arrays
77 | # -----------------------------------------------------------------------------
78 | print(n.shape)
79 | # (3, 3)
80 |
81 | n_slice = n[1:3, 1:3]
82 | print(n_slice)
83 | # [[ 45 101]
84 | # [ 60 10]]
85 |
86 | single_value = n[1, 2]
87 | print(single_value)
88 | # 101
89 |
90 | # iterate through an array:
91 | for i in n:
92 | print(i)
93 | # [ 12 45 255]
94 | # [ 34 45 101]
95 | # [122 60 10]
96 |
97 | # iterate through columns instead for rows by using the transpose method:
98 | for i in n.T:
99 | print(i)
100 | # [ 12 34 122]
101 | # [45 45 60]
102 | # [255 101 10]
103 |
104 | # iterate through each value by using the flat method:
105 | for i in n.flat:
106 | print(i, end=', ')
107 | print('')
108 | # 12, 45, 255, 34, 45, 101, 122, 60, 10,
109 |
110 |
111 | # Stacking and splitting arrays
112 | # -----------------------------------------------------------------------------
113 | stacked_array = numpy.hstack((n, n))
114 | print(stacked_array)
115 | # [[ 12 45 255 12 45 255]
116 | # [ 34 45 101 34 45 101]
117 | # [122 60 10 122 60 10]]
118 |
119 | stacked_array = numpy.vstack((n, n))
120 | print(stacked_array)
121 | # [[ 12 45 255]
122 | # [ 34 45 101]
123 | # [122 60 10]
124 | # [ 12 45 255]
125 | # [ 34 45 101]
126 | # [122 60 10]]
127 |
128 | # Note you can stack together (concatenate) as many arrays as you want
129 | # (provided they have the same dimensions):
130 |
131 | stacked_array = numpy.hstack((n, n, n.T, n.T))
132 | print(stacked_array)
133 | # [[ 12 45 255 12 45 255 12 34 122 12 34 122]
134 | # [ 34 45 101 34 45 101 45 45 60 45 45 60]
135 | # [122 60 10 122 60 10 255 101 10 255 101 10]]
136 |
137 | split_array = numpy.hsplit(stacked_array, 2)
138 | for i in split_array:
139 | print(i)
140 | # [[ 12 45 255 12 45 255]
141 | # [ 34 45 101 34 45 101]
142 | # [122 60 10 122 60 10]]
143 | # [[ 12 34 122 12 34 122]
144 | # [ 45 45 60 45 45 60]
145 | # [255 101 10 255 101 10]]
146 |
147 | split_array = numpy.vsplit(stacked_array, 3)
148 | for i in split_array:
149 | print(i)
150 | # [[ 12 45 255 12 45 255 12 34 122 12 34 122]]
151 | # [[ 34 45 101 34 45 101 45 45 60 45 45 60]]
152 | # [[122 60 10 122 60 10 255 101 10 255 101 10]]
153 |
--------------------------------------------------------------------------------
/operators.py:
--------------------------------------------------------------------------------
1 | '''Operators'''
2 |
3 |
4 | a = 4
5 | b = 5
6 |
7 |
8 | # Arithmetic operators
9 | # -----------------------------------------------------------------------------
10 |
11 | print(a + b) # Add
12 | print(a - b) # Subtract
13 | print(a * b) # Multiply
14 | print(a / b) # Divide
15 | print(a // b) # Floor division: digits after the decimal are dropped
16 | print(a % b) # Modulus: divides and returns the remainder of the first number
17 | print(a ** b) # Exponent calculation
18 |
19 |
20 | # Comparison operators
21 | # -----------------------------------------------------------------------------
22 |
23 | print(a > b) # Greater than
24 | print(a < b) # Less than
25 | print(a >= b) # Greater or equal to
26 | print(a <= b) # Less or equal to
27 | print(a == b) # Equal to
28 | print(a != b) # Not equal to
29 |
30 |
31 | # Assignment operators
32 | # -----------------------------------------------------------------------------
33 |
34 | a = b # Assigns the values from the right to the left
35 | print(a) # 5
36 | a += b # Equivalent to a = a + b
37 | print(a) # 10
38 | a -= b # Equivalent to a = a - b
39 | print(a) # 5
40 | a *= b # Equivalent to a = a * b
41 | print(a) # 25
42 | a /= b # Equivalent to a = a / b
43 | print(a) # 5.0
44 | a //= b # Equivalent to a = a // b
45 | print(a) # 1.0
46 | a %= b # Equivalent to a = a % b
47 | print(a) # 1.0
48 | a **= b # Equivalent to a = a ** b
49 | print(a) # 1.0
50 |
51 |
52 | # Get // and % with divmod()
53 | # -----------------------------------------------------------------------------
54 |
55 | a = 4
56 | b = 5
57 |
58 | c = divmod(a, b) # will return the quotient and the remainder as a tuple
59 | print(c) # (0, 4)
60 | print(type(c)) #
61 |
62 | # NOTE: when working with modulus or divmod, keep in mind that when dividing
63 | # a larger number into a smaller number, the quotient will be always be zero
64 | # and the remainder will be the first number. This may seem obvious but still
65 | # worth noting.
66 |
67 |
68 | # Assignment-expression (walrus) operator :=
69 | # -----------------------------------------------------------------------------
70 | # New to Python 3.8 and one of the things we lost Guido over, the
71 | # assignment-expression operator (walrus) allows you to make an assignment and
72 | # use the result at the same time.
73 |
74 | # For example:
75 |
76 | a = [1, 2, 3, 4, 5, 6, 7]
77 |
78 | # Without walrus:
79 |
80 | if len(a) > 5:
81 | print(f'List too long (expected 5, got {len(a)}).')
82 | # List too long (expected 5, got 7).
83 |
84 | # With walrus:
85 |
86 | if (n := len(a)) > 5:
87 | print(f'List too long (expected 5, got {n}).')
88 | # List too long (expected 5, got 7).
89 |
90 | # Another example use case could be a list comprehensions where
91 | # a value computed in the filtering condition is also needed in
92 | # the expression body. In other words, share a subexpression
93 | # between a comprehension filter clause and its output.
94 |
95 | # For example:
96 |
97 | data = ['one', 'two', 'cheese', 'xxxxxxxxxx']
98 |
99 | def func(arg):
100 | # pretend a bunch of processing happening here
101 | if len(arg) < 10:
102 | result = arg
103 | else:
104 | result = None
105 | return result
106 |
107 |
108 | filtered = [result.title() for d in data if (result := func(d)) is not None]
109 |
110 | print(filtered)
111 | # ['One', 'Two', 'Cheese']
112 |
113 | # The operator is also useful with while-loops that compute a value
114 | # to test loop termination and then need that same value again in the
115 | # body of the loop.
116 |
117 | # For example:
118 |
119 | def process(block):
120 | # pretend a bunch of processing happening here
121 | print(block)
122 |
123 | with open('data/example.txt', 'r') as file:
124 | while (block := file.read(5)) != '':
125 | process(block)
126 |
127 |
128 | # Dictionary merge and update operators
129 | # -----------------------------------------------------------------------------
130 | # Python 3.9 introduced the '|' and '|=' operators for dictionaries to
131 | # "complement" existing dict.update and {**d1, **d2} methods of merging
132 | # dictionaries.
133 |
134 | d = {'spam': 1, 'eggs': 2, 'cheese': 3}
135 | e = {'cheese': 'cheddar', 'fruit': 'apple'}
136 |
137 | f = d | e
138 | # {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'fruit': 'apple'}
139 | g = e | d
140 | # {'cheese': 3, 'fruit': 'apple', 'spam': 1, 'eggs': 2}
141 | d |= e
142 | # {'spam': 1, 'eggs': 2, 'cheese': 'cheddar', 'fruit': 'apple'}
143 |
--------------------------------------------------------------------------------
/package_management.md:
--------------------------------------------------------------------------------
1 | # Package Management
2 |
3 | ## Table of contents
4 |
5 |
6 |
7 | - [pip](#pip)
8 | - [Installing & upgrading packages](#installing--upgrading-packages)
9 | - [pip help](#pip-help)
10 | - [Requirements files](#requirements-files)
11 | * [pipreqs](#pipreqs)
12 | - [Dependencies](#dependencies)
13 | * [pipdeptree](#pipdeptree)
14 |
15 |
16 |
17 | ## pip
18 |
19 | *`pip`* - you can install most python packages this way
20 | *package managers* - (ie brew) work like pip but not restricted to python
21 |
22 | NOTE: Usually, pip is automatically installed if you installed Python from python.org or you're working in virtual environment. You can see where the pip command is looking, for example:
23 |
24 | A Python installation on mac os might look like:
25 |
26 | ```bash
27 | $ which pip
28 | /usr/local/bin/pip
29 | ```
30 |
31 | If using [pyenv](https://github.com/pyenv/pyenv), the path may look like this:
32 |
33 | ```bash
34 | $ which pip
35 | /Users/jessicarush/.pyenv/shims/pip
36 | ```
37 |
38 | If activating a virtual environment, it should point to the `venv` directory in our project folder:
39 |
40 | ```bash
41 | $ source venv/bin/activate
42 | $ which pip
43 | /Users/jessicarush/Documents/Coding/Python/github_python/venv/bin/pip
44 | ```
45 |
46 | You can check the path and the version with `pip --version`:
47 |
48 | ```bash
49 | $ pip --version
50 | pip 21.2.4 from /Users/jessicarush/.pyenv/versions/3.10.2/lib/python3.10/site-packages/pip (python 3.10)
51 | ```
52 |
53 | to upgrade pip (the order matters):
54 |
55 | ```bash
56 | $ pip install --upgrade pip
57 | ```
58 |
59 |
60 | ## Installing & upgrading packages
61 |
62 | Install the most recent version of something:
63 |
64 | ```bash
65 | $ pip install flask
66 | ```
67 |
68 | Upgrade an already installed package:
69 |
70 | ```bash
71 | $ pip install --upgrade flask
72 | ```
73 |
74 | Install a particular version:
75 |
76 | ```bash
77 | $ pip install flask==2.0.3
78 | ```
79 |
80 | Install a minimum version:
81 |
82 | ```bash
83 | $ pip install flask>==0.9.0
84 | ```
85 |
86 | To see where a package is installed:
87 |
88 | ```bash
89 | $ pip show flask
90 | ```
91 |
92 | Run the following command to check if any of your packages can be updated.
93 |
94 | ```bash
95 | $ pip list --outdated
96 | ```
97 |
98 | There's another library that does this way better. It shows which packages have a minor vs major updates and formats the output really nice:
99 |
100 | ```bash
101 | $ pip install pip-check
102 | $ pip-check
103 | ```
104 |
105 |
106 | ## pip help
107 |
108 | To access pip's help documentation you can type `pip help` in the command line. You can also follow that with a specific command you want help with, for example:
109 |
110 | ```bash
111 | pip help install
112 | ```
113 |
114 | This will give you all sorts of useful stuff including what all the various flags mean.
115 |
116 |
117 | ## Requirements files
118 |
119 | [Requirements files](https://pip.pypa.io/en/latest/user_guide/#requirements-files) are files containing a list of packages to be installed using pip install. Logically, a requirements file is just a list of pip install arguments placed in a file. Note that you should not rely on the items in the file being installed by pip in any particular order.
120 |
121 | Requirements files are used to hold the result from `pip freeze` for the purpose of achieving repeatable installations. Your requirement file contains a pinned version of everything that was installed when pip freeze was run.
122 |
123 | To list all the installed packages:
124 |
125 | ```bash
126 | $ pip freeze
127 | ```
128 |
129 | To output the list to a file:
130 |
131 | ```bash
132 | $ pip freeze > requirements.txt
133 | ```
134 |
135 | To install from the file:
136 |
137 | ```bash
138 | $ pip install -r requirements.txt
139 | ```
140 |
141 | NOTE: `pip freeze` saves all packages that are currently installed in the environment.
142 |
143 | NOTE: `pip freeze` only lists the packages that were installed using pip in your environment. If you installed other packages in a different way, or you need to add something that's required for the production server, just add it manually to the `requirements.txt` file.
144 |
145 | ### pipreqs
146 |
147 | [pipreqs](https://github.com/bndr/pipreqs) is a package used to generate a `requirements.txt` file for any project based on imports.
148 |
149 | ```bash
150 | $ pip install pipreqs
151 | ```
152 |
153 | Once pipreqs is installed:
154 |
155 | ```bash
156 | $ pipreqs path/to/project/directory
157 | ```
158 |
159 | That being said, the github page reports quite a few open issues. You're better off starting with a clean virtual environment and using pip to install everything you need as you go, thereby ensuring your pip freeze will be accurate and up-to-date.
160 |
161 |
162 | ## Dependencies
163 |
164 | This will list all package dependencies:
165 |
166 | ```bash
167 | $ pip show flask | grep Requires
168 | Requires: click, Jinja2, Werkzeug, itsdangerous
169 | ```
170 |
171 | ### pipdeptree
172 |
173 | The [pipdeptree](https://github.com/naiquevin/pipdeptree) package will show the whole family tree of dependencies in your environment.
174 |
175 | ```bash
176 | $ pip install pipdeptree
177 | ```
178 |
179 | Just run the command:
180 |
181 | ```bash
182 | $ pipdeptree
183 | ```
184 |
185 | Requirements files are used to force pip to properly resolve dependencies. As it is now, pip doesn't have true dependency resolution, but instead simply uses the first specification it finds for a project. For example, if pkg1 requires pkg3 >=1.0 and pkg2 requires pkg3 >=1.0, <=2.0, and if pkg1 is resolved first, pip will only use pkg3 >=1.0, and could easily end up installing a version of pkg3 that conflicts with the needs of pkg2. To solve this problem, you can place pkg3 >=1.0, <=2.0 (the correct specification) into your requirements file directly along with the other top level requirements. Like so:
186 |
187 | ```text
188 | pkg1
189 | pkg2
190 | pkg3>=1.0,<=2.0
191 | ```
192 |
--------------------------------------------------------------------------------
/postgreSQL_example.py:
--------------------------------------------------------------------------------
1 | '''PostgreSQL'''
2 |
3 |
4 | # To work with this database server, first you'll need to download the
5 | # installer: https://www.postgresql.org/
6 |
7 | # Launch the installer and it will take you into the 'setup wizard'.
8 | # Choose your installation directory, data directory, (by default these are
9 | # /Library/PostgreSQL/10/data). Then you'll need to create a superuser
10 | # password. The superuser is 'postgres' by default but you select the password.
11 | # It's a good idea to record all this in a credentials file including the
12 | # next item which is port. By default is: 5432.
13 |
14 | # The next question 'Set the locale to be used by the new database cluster'.
15 | # There's a good description of database clusters here:
16 | # https://www.postgresql.org/docs/current/static/creating-cluster.html
17 | # Locale refers to an application respecting cultural preferences regarding
18 | # alphabets, sorting, number formatting, etc. If your system is already set to
19 | # use the locale that you want in your database cluster then there is nothing
20 | # else you need to do. If you want to use a different locale you can select
21 | # something else from the list. Note, you can't change this afterwards.
22 |
23 | # After the main install completes, it will ask you if you want some additional
24 | # tools (Stack Builder). There's bunch of add-ons available here. You can
25 | # access this current list of add-ons at any time by launching stackbuilder:
26 | # /Library/PostgreSQL/10/stackbuilder
27 |
28 | # Next, you'll need to use the pgAdmin tool to create a database. Once the
29 | # dashboard tool opens, right click on the PostgreSQL server in the left
30 | # panel and choose 'Connect Server'. Type your password. Once connected,
31 | # pop open the Databases group and you'll see one default database called
32 | # 'postgres'. To create a new one, right click on the 'Databases' group and
33 | # choose 'Create' > database.
34 |
35 | # You could use the included tools in this directory to interact with the
36 | # PostgreSQL database, or you could use python with the help of an external
37 | # library psycopg2: http://initd.org/psycopg/
38 |
39 | # NOTE: once you've created the database, you can check out the table in
40 | # the pgAdmin tool. Navigate to your database > Schemas > Public > Tables
41 | # There's also a query tool that allows you to query your database.
42 |
43 | # NOTE: for some reason PostgreSQL doesn't like the syntax of using ? as
44 | # placeholder values. It prefers %s instead!
45 |
46 | # NOTE: do not use the name 'user' for a table name as is is a reserved word
47 | # in postgresql. 'users' seems to work fine.
48 |
49 | import psycopg2
50 |
51 |
52 | db = ("dbname='test1'"
53 | "user='postgres'"
54 | "password='your-password'"
55 | "host='localhost'"
56 | "port='5432'")
57 |
58 |
59 | def create():
60 | conn = psycopg2.connect(db)
61 | curs = conn.cursor()
62 | curs.execute('''CREATE TABLE IF NOT EXISTS inventory
63 | (item TEXT, quantity INT, cost FLOAT)''')
64 | conn.commit()
65 | curs.close()
66 | conn.close()
67 |
68 |
69 | def insert(item, quantity, cost):
70 | conn = psycopg2.connect(db)
71 | curs = conn.cursor()
72 | curs.execute("INSERT INTO inventory VALUES (%s, %s, %s)",
73 | (item, quantity, cost))
74 | curs.connection.commit()
75 | curs.close()
76 | conn.close()
77 |
78 |
79 | def display():
80 | conn = psycopg2.connect(db)
81 | curs = conn.cursor()
82 | curs.execute('SELECT * FROM inventory')
83 | rows = curs.fetchall()
84 | curs.close()
85 | conn.close()
86 | return rows
87 |
88 |
89 | def delete(item):
90 | conn = psycopg2.connect(db)
91 | curs = conn.cursor()
92 | curs.execute('DELETE FROM inventory WHERE item=%s', (item,))
93 | curs.connection.commit()
94 | curs.close()
95 | conn.close()
96 |
97 |
98 | def update(quantity, cost, item):
99 | conn = psycopg2.connect(db)
100 | curs = conn.cursor()
101 | curs.execute('UPDATE inventory SET quantity=%s, cost=%s WHERE item=%s',
102 | (quantity, cost, item))
103 | curs.connection.commit()
104 | curs.close()
105 | conn.close()
106 |
107 |
108 | create()
109 | insert('Dolphin', 5, 1000)
110 | # insert('Rocks', 5, 2)
111 | # insert('Dice', 100, 0.5)
112 | # delete('Dice')
113 | update(5000, 0.5, 'Giraffe')
114 | print(display())
115 |
116 |
117 |
118 | # To compare: sqlite3
119 | # -----------------------------------------------------------------------------
120 | # The following is the same code but written for sqlite3:
121 |
122 | import sqlite3
123 |
124 | db = 'data/test.db'
125 |
126 | def create():
127 | conn = sqlite3.connect(db)
128 | curs = conn.cursor()
129 | curs.execute('''CREATE TABLE IF NOT EXISTS inventory
130 | (item TEXT, quantity INT, cost FLOAT)''')
131 | conn.commit()
132 | curs.close()
133 | conn.close()
134 |
135 |
136 | def insert(item, quantity, cost):
137 | conn = sqlite3.connect(db)
138 | curs = conn.cursor()
139 | curs.execute('INSERT INTO inventory VALUES (?, ?, ? )',
140 | (item, quantity, cost))
141 | curs.connection.commit()
142 | curs.close()
143 | conn.close()
144 |
145 |
146 | def display():
147 | conn = sqlite3.connect(db)
148 | curs = conn.cursor()
149 | curs.execute('SELECT * FROM inventory')
150 | rows = curs.fetchall()
151 | curs.close()
152 | conn.close()
153 | return rows
154 |
155 |
156 | def delete(item):
157 | conn = sqlite3.connect(db)
158 | curs = conn.cursor()
159 | curs.execute('DELETE FROM inventory WHERE item=?', (item,))
160 | curs.connection.commit()
161 | curs.close()
162 | conn.close()
163 |
164 |
165 | def update(quantity, cost, item):
166 | conn = sqlite3.connect(db)
167 | curs = conn.cursor()
168 | curs.execute('UPDATE inventory SET quantity=?, cost=? WHERE item=?',
169 | (quantity, cost, item))
170 | curs.connection.commit()
171 | curs.close()
172 | conn.close()
173 |
174 |
175 | create()
176 | # insert('Coffee', 25, 10.5)
177 | # insert('Rocks', 5, 2)
178 | # insert('Dice', 100, 0.5)
179 | # delete('Rocks')
180 | update(100, 0.5, 'Dice')
181 | print(display())
182 |
--------------------------------------------------------------------------------
/postman.md:
--------------------------------------------------------------------------------
1 | # Postman App for API testing
2 |
3 |
4 | https://www.getpostman.com/
5 |
6 | Postman is an API development application that makes it easy to create, save and test your API requests during development. Once you've downloaded the software for your OS, launch it. You don't have to create an account but you should create a project folder in collections. Note you can also create sub folders. Once you're ready to test:
7 |
8 | - Make sure your web server is running.
9 | - Choose the http verb you want to test (GET, POST, etc).
10 | - Enter the address (ie http://localhost:5000/store).
11 | - Press the send button to test out your request.
12 | - Save your requests to the appropriate collection/sub-collection so you don't need to type it out again.
13 | - Once saved, select it in the sidebar to edit or duplicate it to create more variations.
14 |
15 | Testing GET requests is pretty straightforward but testing POST requests requires a little more information. Go to the headers tab (the first thing flask does when it gets a request, is look at the headers to see what sort of data it's getting). Here you can add key-value pairs like:
16 |
17 | ```
18 | Content-Type application/json
19 | ```
20 |
21 | With this information in, we can now go to the body tab and enter in the data that we want to send with the POST request. For example, choose the 'raw' option and type something like:
22 |
23 | ```
24 | {"name": "Flying Potato"}
25 | ```
26 |
27 | > :warning: JSON always uses double quotes.
28 |
29 | If you're working with JWT for authorization, you will need to add the token by clicking on the headers tab, type Authorization for the key and for the value type JWT followed by one space, then the token (no quotes).
30 |
31 | ```
32 | JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
33 | ```
34 |
35 | > :bookmark: If you're sick of seeing/typing the main part of the url in your endpoints, you can always set up an environment variable. When you do this, all your endpoints can be changed from the first example to the second:
36 |
37 | ```
38 | http://localhost:5000/item/
39 | {{url}}/item/
40 | ```
41 |
42 | To set up an environment variable in postman, first you'll need to create a new environment. Click the 'eye' icon in the top right corner. Add an environment, give it a name. You can switch environments using the select menu beside the eye icon.
43 |
44 | In the same menu, you can add global variables to your active environment. For example, with the url above we'd set `url` as they variable and `http://localhost:5000` as the value. Don't forget to hit the **save** button.
45 |
46 | You can set up something similar for JWT tokens so you're not copying and pasting all the time. Where you would normally enter the token value, enter instead:
47 |
48 | ```
49 | JWT {{token}}
50 | ```
51 |
52 | Go to the end point that produces the token {{url}}/auth and click on the Tests tab. This area is for Javascript code. It will run after the request has been processed by the server and sent back to us. What we can do in the test area is use the token thats just been issued and use it to change the environment variable {{token}}. In the test area:
53 |
54 | ```Javascript
55 | pm.test("Access Token Test", function () {
56 | var jsonData = pm.response.json();
57 | pm.expect(jsonData.access_token).to.not.eql(null);
58 | pm.environment.set("token", jsonData.access_token);
59 | });
60 | ```
61 |
62 | This comes from the snippets: "Response Body:JSON value check" and "Set an environment variable".
63 |
64 | Now when you send the /auth endpoint, you should see "Test Results 1/1" passed at the bottom where the return data is displayed. And, when you send your endpoint that requires the token, it should now pick up the current environment variable. Note you can always see your variables by clicking the eye icon.
65 |
--------------------------------------------------------------------------------
/pyenv.md:
--------------------------------------------------------------------------------
1 | # pyenv
2 |
3 | See first: [pyenv docs](https://github.com/pyenv/pyenv)
4 |
5 | These instructions come from this [intro to pyenv article](https://realpython.com/intro-to-pyenv/), but [this blog post](https://switowski.com/blog/pyenv) also looks good.
6 |
7 | ## Table of Contents
8 |
9 |
10 |
11 | - [Install pyenv](#install-pyenv)
12 | - [Install python versions](#install-python-versions)
13 | - [Remove a version](#remove-a-version)
14 | - [Using your versions](#using-your-versions)
15 | - [Other commands](#other-commands)
16 |
17 |
18 |
19 | ## Install pyenv
20 |
21 | Install dependencies:
22 |
23 | ```bash
24 | brew install openssl readline sqlite3 xz zlib
25 | ```
26 |
27 | Install pyenv:
28 |
29 | ```bash
30 | curl https://pyenv.run | bash
31 | ```
32 |
33 | Note: the most recent instruction in the pyenv docs say you can just do this:
34 |
35 | ```bash
36 | brew update
37 | brew install pyenv
38 | ```
39 |
40 | There will be a message in the console saying that you need to update your PATH. Be sure to read because the instructions seem to change as they update pyenv.
41 |
42 | Basically, I have to add to my `.bash_profile`:
43 |
44 | ```bash
45 | export PATH="$HOME/.pyenv/shims:$PATH"
46 | ```
47 |
48 | However, they have a longer, roundabout way of doing this:
49 |
50 | ```bash
51 | export PYENV_ROOT="$HOME/.pyenv"
52 | export PATH="$PYENV_ROOT/bin:$PATH"
53 | eval "$(pyenv init --path)"
54 | eval "$(pyenv init -)"
55 | ```
56 |
57 | The reasons are explained in the [pyenv docs](https://github.com/pyenv/pyenv#advanced-configuration).
58 |
59 | Be sure to restart `.bash_profile`:
60 |
61 | ```bash
62 | source ~/.bash_profile
63 | ```
64 |
65 | ## Install python versions
66 |
67 | List all versions (warning: there's a lot):
68 |
69 | ```bash
70 | pyenv install --list
71 | ```
72 |
73 | List specific versions:
74 |
75 | ```bash
76 | pyenv install --list | grep " 3\.[678]"
77 | ```
78 |
79 | Install a version:
80 |
81 | ```bash
82 | pyenv install -v 3.7.8
83 | ```
84 |
85 | Each version installed with pyenv is located in your pyenv root directory:
86 |
87 | ```bash
88 | ls ~/.pyenv/versions/
89 | ```
90 |
91 | ## Remove a version
92 |
93 | Check the versions you have first:
94 |
95 | ```bash
96 | ls ~/.pyenv/versions/
97 | ```
98 |
99 | Then remove one like this:
100 |
101 | ```bash
102 | rm -rf ~/.pyenv/versions/2.7.15
103 | ```
104 |
105 | or like this:
106 |
107 | ```bash
108 | pyenv uninstall 2.7.15
109 | ```
110 |
111 | ## Using your versions
112 |
113 | First check what you have:
114 |
115 | ```bash
116 | pyenv versions
117 | * system (set by /Users/jessicarush/.pyenv/version)
118 | 3.5.9
119 | 3.6.11
120 | 3.7.8
121 | 3.8.5
122 | ```
123 |
124 | The asterisk indicates which version is currently running. In the above output it's the system os version (2.7.16).
125 |
126 | To switch you can use the `global` command:
127 |
128 | ```bash
129 | pyenv global 3.7.8
130 | ```
131 |
132 | now check:
133 |
134 | ```bash
135 | pyenv versions
136 | system
137 | 3.5.9
138 | 3.6.11
139 | * 3.7.8 (set by /Users/jessicarush/.pyenv/version)
140 | 3.8.5
141 | ```
142 |
143 | A great way to get peace of mind that the version of Python you just installed is working properly is to run the built-in test suite:
144 |
145 | ```bash
146 | python -m test
147 | ```
148 |
149 | If you ever want to go back to the system version:
150 |
151 | ```bash
152 | pyenv global system
153 | ```
154 |
155 | ## Other commands
156 |
157 | Note, you will need to update pyenv to see new python versions to install with `pyenv install --list`. To update pyenv:
158 |
159 | ```bash
160 | pyenv update
161 | ```
162 |
163 | Note that if you want to see `which python`, there will be a pyenv shim in place:
164 |
165 | ```bash
166 | which python
167 | /Users/jessicarush/.pyenv/shims/python
168 | ```
169 |
170 | To see the actual path, you can run the following:
171 |
172 | ```bash
173 | pyenv which python
174 | /usr/bin/python
175 | ```
176 |
177 | To see a complete list of pyenv commands:
178 |
179 | ```bash
180 | pyenv commands
181 | ```
182 |
183 | Each command has a `--help` flag that will give you more detailed information.
184 |
185 | See also: [pyenv commands reference](https://github.com/pyenv/pyenv/blob/master/COMMANDS.md#pyenv-global)
186 |
--------------------------------------------------------------------------------
/pygal_github_api_example.py:
--------------------------------------------------------------------------------
1 | '''Data visualization using a web API'''
2 |
3 |
4 | # A program that downloads current information about the most-starred
5 | # Python projects in GitHub. Some helpful links:
6 |
7 | # https://api.github.com
8 | # https://developer.github.com/v3/search/
9 | # https://help.github.com/articles/searching-repositories/
10 | # https://help.github.com/articles/understanding-the-search-syntax/
11 | # http://docs.python-requests.org
12 |
13 | import requests
14 | import pygal
15 | from pygal.style import LightColorizedStyle as LCS, LightenStyle as LS
16 |
17 |
18 | # Processing an API response
19 | # -----------------------------------------------------------------------------
20 |
21 | # make an API call and store the requests:
22 | url = 'https://api.github.com/search/repositories?q=language:python&sort=stars'
23 | r = requests.get(url)
24 |
25 | # It's always go to check the status - use these to make some asserts.
26 | print('Status code:', r.status_code)
27 | print('Headers:', r.headers['content-type'])
28 | print('Encoding:', r.encoding)
29 | # Status code: 200 (a status code of 200 indicates a successful response)
30 | # Headers: application/json; charset=utf-8
31 | # Encoding: utf-8
32 |
33 | # Store API response in a variable. The API returns info in JSON format so we
34 | # use the json() method to convert to a python dict.
35 | response_dict = r.json()
36 | print(type(response_dict)) # ->
37 |
38 | # process results:
39 | print(response_dict.keys())
40 | print('Total repositories:', response_dict['total_count'])
41 | print('Incomplete results:', response_dict['incomplete_results'])
42 | print('Repositories returned:', len(response_dict['items']))
43 | # dict_keys(['total_count', 'incomplete_results', 'items'])
44 | # Incomplete results: False
45 | # Total repositories: 2077471
46 | # Repositories returned: 30
47 |
48 | repo_dicts = response_dict['items']
49 |
50 | # examine the first repo:
51 | # repo_dict1 = repo_dicts[0]
52 | # print('\nKeys:', len(repo_dict1))
53 | # for key in sorted(repo_dict1.keys()):
54 | # print(key, '–', repo_dict1[key])
55 |
56 |
57 | # Summarizing the top repos
58 | # -----------------------------------------------------------------------------
59 |
60 | print('\nSome information about the top 30 repository:')
61 | for repo_dict in repo_dicts:
62 | print('\nName:', repo_dict['name'])
63 | print('Owner:', repo_dict['owner']['login'])
64 | print('Stars:', repo_dict['stargazers_count'])
65 | print('Repository:', repo_dict['html_url'])
66 | print('Created:', repo_dict['created_at'])
67 | print('Updated:', repo_dict['updated_at'])
68 | print('Description:', repo_dict['description'])
69 |
70 |
71 | # Monitoring API rate limits
72 | # -----------------------------------------------------------------------------
73 |
74 | # most APIs are rate-limited, which means there's a limit to how many requests
75 | # you can make in a certain amount of time. To see if you're approaching
76 | # GitHub's limits: https://api.github.com/rate_limit
77 |
78 |
79 | # Prep the data for plotting:
80 | # -----------------------------------------------------------------------------
81 | #
82 | # names, stars = [], []
83 | # for repo_dict in repo_dicts:
84 | # names.append(repo_dict['name'])
85 | # stars.append(repo_dict['stargazers_count'])
86 |
87 | # NOTE: You can add custom tooltips by passing a list of dictionaries instead
88 | # of a list of values to chart.add() like so:
89 | # plot_dict = [
90 | # {'value': 1314, 'label': 'Description...'},
91 | # {'value': 5670, 'label': 'Description...'},
92 | # {'value': 3224, 'label': 'Description...'},]
93 |
94 | names, plot_dicts = [], []
95 | for repo_dict in repo_dicts:
96 | names.append(repo_dict['name'])
97 | # get the description if one is available:
98 | description = repo_dict['description']
99 | if not description:
100 | description = 'No description provided'
101 | if len(description) > 118:
102 | description = description[:118] + '...'
103 |
104 | # NOTE: pygal uses the value given for 'xlink' to turn each bar into an active
105 | # link to the given url. You can also add links to the legend. See the docs:
106 | # http://pygal.org/en/stable/documentation/configuration/value.html#legend
107 |
108 | plot_dict = {
109 | 'value': repo_dict['stargazers_count'],
110 | 'label': description,
111 | 'xlink' : repo_dict['html_url']
112 | }
113 | plot_dicts.append(plot_dict)
114 |
115 |
116 | # Visualizing the repos with pygal
117 | # -----------------------------------------------------------------------------
118 |
119 | my_style = LS('#25bec4', base_style=LCS)
120 | my_style.title_font_family = 'Helvetica'
121 |
122 | # NOTE: google fonts will only render when the svg is embedded because the
123 | # google stylesheet is added in the XML processing.
124 | # my_style.title_font_family = 'googlefont:Slabo'
125 |
126 | my_style.title_font_size = 14
127 | my_style.foreground = '#586e75'
128 | my_style.foreground_strong = '#334145'
129 | my_style.foreground_subtle = '#fdca32'
130 | my_style.label_font_size = 9
131 | my_style.major_label_font_size = 12
132 | my_style.tooltip_font_size = 11
133 |
134 | my_config = pygal.Config()
135 | my_config.show_legend = False
136 | my_config.truncate_label = 15
137 | my_config.show_y_guides = True
138 | my_config.width = 1000
139 |
140 | my_config.y_labels = list(range(0, 42000, 2000))
141 | my_config.y_labels_major_count = 3
142 | my_config.x_labels = names
143 | my_config.x_label_rotation = 45
144 |
145 | chart = pygal.Bar(my_config, style=my_style)
146 | chart.title = "Most-Starred Python Projects on GitHub"
147 |
148 | # chart.add('', stars)
149 | chart.add('', plot_dicts)
150 | chart.render_to_file('api_pygal_example.svg')
151 |
--------------------------------------------------------------------------------
/pygal_hn_api_example.py:
--------------------------------------------------------------------------------
1 | '''Exploring API Calls'''
2 |
3 |
4 | # The following call returns information about an article on hacker news:
5 | # https://hacker-news.firebaseio.com/v0/item/9884165.json
6 |
7 | # The dictionary contains of number of useful keys like title, url, score.
8 | # The 'descendants' key contains the number of comments an article has.
9 |
10 | import json
11 | from operator import itemgetter
12 |
13 | import requests
14 | import pygal
15 | from pygal.style import DefaultStyle as DS, LightenStyle as LS
16 |
17 |
18 | # Make an API call and store the response:
19 | # -----------------------------------------------------------------------------
20 |
21 | # This API returns a list containing the IDs of top 500 articles on HN:
22 | url = 'https://hacker-news.firebaseio.com/v0/topstories.json'
23 | r = requests.get(url)
24 |
25 | print('Status code:', r.status_code)
26 | print('Headers:', r.headers['content-type'])
27 | print('Encoding:', r.encoding)
28 |
29 |
30 | # Process information about each submission:
31 | # -----------------------------------------------------------------------------
32 |
33 | submission_ids = r.json()
34 | submission_dicts = []
35 | for submission_id in submission_ids[:100]:
36 | # make a separate API call for each submission:
37 | url = ('https://hacker-news.firebaseio.com/v0/item/'
38 | + str(submission_id) + '.json')
39 | submission_r = requests.get(url)
40 | response_dict = submission_r.json()
41 |
42 | submission_dict = {
43 | 'title' : response_dict['title'],
44 | 'link': 'http://news.ycombinator.com/item?id=' + str(submission_id),
45 | 'comments': response_dict.get('descendants', 0),
46 | 'id' : str(submission_id)
47 | }
48 | submission_dicts.append(submission_dict)
49 |
50 |
51 | # Store the dict as a JSON to reuse while testing:
52 | # -----------------------------------------------------------------------------
53 |
54 | with open('hacker_news_api.json', 'w') as fob:
55 | json.dump(submission_dicts, fob)
56 |
57 | with open('hacker_news_api.json') as fob:
58 | submission_dicts = json.load(fob)
59 |
60 |
61 | # Sort the information:
62 | # -----------------------------------------------------------------------------
63 |
64 | submission_dicts = sorted(submission_dicts, key=itemgetter('comments'),
65 | reverse=True)
66 |
67 | submission_dicts = list(submission_dicts[15:0:-1])
68 |
69 | titles, plot_dicts = [], []
70 | for submission_dict in submission_dicts:
71 | title = submission_dict['title']
72 | if len(title) > 100:
73 | title = title[:100] + '...'
74 | titles.append(title)
75 |
76 | plot_dict = {
77 | 'value': submission_dict['comments'],
78 | 'label': submission_dict['id'],
79 | 'xlink' : submission_dict['link'],
80 | 'title' : title
81 | }
82 | plot_dicts.append(plot_dict)
83 |
84 |
85 |
86 | # Style info:
87 | # -----------------------------------------------------------------------------
88 |
89 | style = LS('#25bec4', base_style=DS)
90 |
91 | # style.plot_background = '#586e75'
92 | # style.background = '#586e75'
93 | style.foreground = '#586e75' # all labels, guides
94 | style.foreground_strong = '#13434f' # major labels and title
95 | # style.foreground_subtle = '#fdca32' # minor guides
96 |
97 | # style.font_family = 'Helvetica'
98 | style.title_font_family = 'Helvetica'
99 | style.label_font_family = 'Helvetica'
100 | # style.major_label_font_family = 'Helvetica'
101 | # style.value_font_family = 'Helvetica'
102 | # style.value_label_font_family = 'Helvetica'
103 | # style.tooltip_font_family = 'Helvetica'
104 | # style.legend_font_family = 'Helvetica'
105 | # style.no_data_font_family = 'Helvetica'
106 |
107 | style.title_font_size = 18
108 | style.label_font_size = 13
109 | style.major_label_font_size = 10
110 | # style.value_font_size = 8
111 | # style.value_label_font_size = 8
112 | # style.tooltip_font_size = 11
113 | # style.legend_font_size = 10
114 | # style.no_data_font_size = 48
115 |
116 | # style.guide_stroke_dasharray = '2, 4'
117 | style.major_guide_stroke_dasharray = '2, 4'
118 | style.opacity = '.6'
119 | style.opacity_hover = '.9'
120 | # style.transition = '150ms'
121 | # style.colors = ('#E853A0', '#E8537A', '#E95355', '#E87653', '#E89B53')
122 | # style.value_colors = ()
123 |
124 |
125 | # Config info:
126 | # -----------------------------------------------------------------------------
127 |
128 | config = pygal.Config()
129 | config.width = 1200
130 | # config.height = 500
131 | # config.spacing = 50
132 | # config.x_title = 'x-axis'
133 | # config.y_title = 'y-axis'
134 | # config.human_readable = True # for complex or large numbers
135 | # config.stroke = False # for line graphs
136 | # config.fill = True # for line graphs
137 | # config.show_dots = False # for line graphs
138 | # config.dots_size = 5 # for line graphs
139 | # config.rounded_bars = 20 # for bar graphs
140 | # config.half_pie = True # for pie charts
141 | # config.inner_radius = .6 # for pie charts
142 |
143 | # config.margin = 0
144 | # config.margin_top = 10
145 | config.margin_right = 100
146 | # config.margin_bottom = 10
147 | config.margin_left = -40
148 |
149 | config.show_legend = False
150 | # config.truncate_legend = -1
151 | # config.legend_box_size = 15
152 | # config.legend_at_bottom = True
153 | # config.legend_at_bottom_columns = 4
154 |
155 | config.show_x_labels = True
156 | config.x_labels = titles
157 | # config.x_label_rotation = 45
158 | # config.x_labels_major = [0, 5, 10]
159 | # config.x_labels_major_every = 3
160 | # config.x_labels_major_count = 5
161 | # config.show_minor_x_labels = True
162 |
163 | config.show_y_labels = True
164 | # config.y_labels = names
165 | # config.y_label_rotation = 45
166 | # config.y_labels_major = [0, 50, 100]
167 | config.y_labels_major_every = 1
168 | # config.y_labels_major_count = 2
169 | config.show_minor_y_labels = True
170 |
171 | # config.truncate_label = 15
172 |
173 | # config.inverse_y_axis = True
174 | # config.inverse_x_axis = True
175 | # config.print_values = True
176 | # config.dynamic_print_values = True
177 | # config.tooltip_border_radius = 3
178 | # config.show_y_guides = True
179 | # config.show_x_guides = True
180 |
181 |
182 | # Create and populate the plot:
183 | # -----------------------------------------------------------------------------
184 |
185 | chart = pygal.HorizontalBar(config, style=style)
186 | chart.title = "Most-commented articles on Hacker News top 100"
187 |
188 | chart.add('', plot_dicts)
189 |
190 | chart.render_to_file('hacker_news_api.svg')
191 |
--------------------------------------------------------------------------------
/pygal_json_example.py:
--------------------------------------------------------------------------------
1 | '''Pygal - Mapping Global Data Sets: JSON format'''
2 |
3 |
4 | # The data in this example comes from:
5 | # http://data.okfn.org/
6 |
7 | # To use the pygal world maps, you need to install it:
8 | # pip install pygal_maps_world
9 |
10 | import json
11 | import pygal
12 | from pygal.maps.world import COUNTRIES
13 | from pygal.maps.world import World
14 | from pygal.style import Style
15 |
16 |
17 | # Explore/Analyze the data
18 | # -----------------------------------------------------------------------------
19 |
20 | # load the data into a list:
21 | filename = 'data/population_data.json'
22 | with open(filename) as fob:
23 | pop_data = json.load(fob)
24 |
25 | # print one year for each country:
26 | for pop_dict in pop_data:
27 | if pop_dict['Year'] == '2010':
28 | country_name = pop_dict['Country Name']
29 | # some of the populations strings have decimals. In order to
30 | # convert them all to ints, we need to convert to floats first.
31 | population = int(float(pop_dict['Value']))
32 | print(country_name, '–', population)
33 |
34 |
35 | # Extract the data
36 | # -----------------------------------------------------------------------------
37 | # To use pygals mapping tools, countries need to be provided as country codes.
38 | # Pygals country codes are stored in a module called pygal_maps_world is a
39 | # dictionary called COUNTRIES. You have to do a separate pip install for this:
40 | # $ pip install pygal_maps_world. Then: pygal.maps.world import COUNTRIES
41 |
42 | for country_code in sorted(COUNTRIES.keys()):
43 | print(country_code, COUNTRIES[country_code])
44 |
45 | def get_country_code(country_name):
46 | '''Return the Pygal 2-digit country code for a given country.'''
47 | for code, name in COUNTRIES.items():
48 | if name == country_name:
49 | return code
50 | # if the name isn't found, return None:
51 | return None
52 |
53 | # Test it out:
54 | cc_populations = {}
55 | for pop_dict in pop_data:
56 | if pop_dict['Year'] == '2010':
57 | country_name = pop_dict['Country Name']
58 | population = int(float(pop_dict['Value']))
59 | code = get_country_code(country_name)
60 | if code:
61 | cc_populations[code] = population
62 | else:
63 | print('Error –', country_name)
64 |
65 | # There are a quite a few Errors (obv) which fall mainly into two categories:
66 | # – some country names don't match exactly (ie Yemen, Rep vs Yemen)
67 | # – some lines in the dataset aren't by country at all but by region
68 | # (ie Arab World) or by economic group (ie all income levels).
69 |
70 | # For the moment, we'll just plot the stuff that matched.
71 |
72 |
73 | # Plot the data
74 | # -----------------------------------------------------------------------------
75 | # group the countries into 3 population levels to have the colouring be more
76 | # informative (otherwise it just shows China and India a contrastig colour).
77 |
78 | cc_pop1, cc_pop2, cc_pop3 = {}, {}, {}
79 | for cc, pop in cc_populations.items():
80 | if pop < 10000000: # 10 million
81 | cc_pop1[cc] = pop
82 | elif pop < 1000000000: # 1 billion
83 | cc_pop2[cc] = pop
84 | else:
85 | cc_pop3[cc] = pop
86 |
87 | # see how many countries are in each group:
88 | print(len(cc_pop1), len(cc_pop2), len(cc_pop3))
89 | # 85, 69, 2
90 |
91 | my_style = Style(
92 | legend_font_size=9,
93 | colors=('#509aff', '#01e7d4', '#ff6e67'))
94 |
95 | wm = World(style=my_style)
96 | wm.title = 'World Population in 2010'
97 |
98 | # wm.add('North America',['ca', 'mx', 'us'])
99 | # wm.add('North America',{'ca': 34126000, 'mx': 113423000, 'us': 309349000})
100 | # wm.add('2010', cc_populations)
101 |
102 | wm.add('0-10m', cc_pop1)
103 | wm.add('10m-1b', cc_pop2)
104 | wm.add('>1b', cc_pop3)
105 |
106 | wm.render_to_file('demos/americas.svg')
107 |
--------------------------------------------------------------------------------
/recursion.py:
--------------------------------------------------------------------------------
1 | '''Recursion'''
2 |
3 |
4 | # Recursion is a way of programming or coding a problem, in which a function
5 | # calls itself one or more times in its body. Usually, it is returning the
6 | # return value of this function call. Put simply, a recursive function is a
7 | # function that calls itself.
8 |
9 |
10 | # Factorial
11 | # -----------------------------------------------------------------------------
12 |
13 | def factorial_i(n):
14 | '''calculates n! iteratively'''
15 | # for example 5! = 5 * 4 * 3 * 2 * 1 = 120
16 | result = 1
17 | if n > 1:
18 | for f in range(2, n + 1):
19 | result *= f
20 | return result
21 |
22 |
23 | # With factorials, you can also say that 6! = 6 * 5!, which is to say you can
24 | # get the factorial of 6 by multiplying 6 * 5's factorial (120).
25 |
26 | def factorial_r(n):
27 | '''calculates n! recursively'''
28 | # n! can also be defined as n * (n-1)!
29 | if n <= 1:
30 | return 1
31 | else:
32 | return n * factorial_r(n - 1)
33 |
34 | # Termination condition: A recursive function has to terminate to be useable
35 | # in a program. A recursive function terminates, if with every recursive call
36 | # the solution of the problem is downsized and moves towards a base case.
37 | # A base case is, where the problem can be solved without further recursion.
38 | # A recursion can lead to an infinite loop, if the base case is not met. In
39 | # the example above, the base case it met by if n <= 1, return 1
40 |
41 | # testing:
42 | for i in range(6):
43 | print(i, factorial_i(i))
44 | # 0 1
45 | # 1 1
46 | # 2 2
47 | # 3 6
48 | # 4 24
49 | # 5 120
50 |
51 | for i in range(6):
52 | print(i, factorial_r(i))
53 | # 0 1
54 | # 1 1
55 | # 2 2
56 | # 3 6
57 | # 4 24
58 | # 5 120
59 |
60 |
61 | # Fibonacci
62 | # -----------------------------------------------------------------------------
63 |
64 | def fib_i(n):
65 | '''Calculates fibonacci iteratively'''
66 | a, b = 0, 1
67 | for i in range(n):
68 | a, b = b, a + b
69 | return a
70 |
71 | def fib_r(n):
72 | '''Calculates fibonacci recursively'''
73 | if n < 2:
74 | return n
75 | else:
76 | return fib_r(n - 1) + fib_r(n - 2)
77 |
78 | def fib_g(n):
79 | '''Calculates fibonacci with a generator'''
80 | a, b = 0, 1
81 | counter = 0
82 | while counter < n:
83 | yield a
84 | a, b = b, a + b
85 | counter += 1
86 |
87 | # testing:
88 | for i in range(10):
89 | print(fib_i(i))
90 | # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
91 |
92 | for i in range(10):
93 | print(fib_r(i))
94 | # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
95 |
96 | fib_generator = fib_g(10)
97 | for i in fib_generator:
98 | print(i)
99 | # 0, 1, 1, 2, 3, 5, 8, 13, 21, 34
100 |
101 |
102 | # Directory Listings
103 | # -----------------------------------------------------------------------------
104 |
105 | import os
106 |
107 | # os.walk() creates a generator object that yields a 3-item tuple
108 | # (dirpath, dirnames, filenames). dirpath is a string of the path to the
109 | # directory. dirnames is a list of the names of the subdirectories in dirpath
110 | # (excluding '.' and '..'). filenames is a list of the names of the
111 | # non-directory files in dirpath.
112 |
113 | # This is a non-recursive example:
114 |
115 | listing = os.walk('.')
116 |
117 | print(next(listing))
118 |
119 | for root, directories, files in listing:
120 | print('Root: ', root)
121 | for d in directories:
122 | print('Directories: ', d)
123 | for f in files:
124 | print('Files: ', f)
125 |
126 | # here we use os.listdir and os.path to create a recursive example:
127 |
128 | def list_directory(s):
129 | def dir_list(d):
130 | nonlocal tab_stop
131 | files = os.listdir(d)
132 | for f in files:
133 | current_dir = os.path.join(d, f)
134 | if os.path.isdir(current_dir):
135 | print('\t' * tab_stop + 'Directory: ' + f)
136 | tab_stop += 1
137 | dir_list(current_dir)
138 | tab_stop -= 1
139 | else:
140 | print('\t' * tab_stop + f)
141 |
142 | tab_stop = 0
143 | if os.path.exists(s):
144 | print('Directory listing of ' + s)
145 | dir_list(s)
146 | else:
147 | print(s + ' does not exist')
148 |
149 |
150 | list_directory('./data')
151 |
152 |
153 | # Tips:
154 | # -----------------------------------------------------------------------------
155 | # When coding/testing a recursive function, it's often helpful to insert print
156 | # statements to see what's going on. When you do this, add a tab before the
157 | # print so you can visually see your levels of recursion.
158 |
--------------------------------------------------------------------------------
/resources.py:
--------------------------------------------------------------------------------
1 | '''Resources'''
2 |
3 |
4 | # Python philosophy
5 | # -----------------------------------------------------------------------------
6 |
7 | import this
8 |
9 |
10 | # Good explanations
11 | # -----------------------------------------------------------------------------
12 | # Python Docs- https://docs.python.org/3/
13 | # Built-ins: https://www.programiz.com/python-programming/methods/built-in
14 | # http://simeonfranklin.com/blog/2012/jul/1/python-decorators-in-12-steps/
15 |
16 |
17 | # When looking for code
18 | # -----------------------------------------------------------------------------
19 | # PyPI - https://pypi.python.org/pypi
20 | # Github - https://github.com/trending?l=python
21 | # Active State - http://code.activestate.com/recipes/langs/python/
22 |
23 |
24 | # help()
25 | # -----------------------------------------------------------------------------
26 | # In the python interpreter, use the help function to get information on a
27 | # module or built-in function, or run the help utility to get information on
28 | # keywords, symbols, topics, modules and built-in functions. For example:
29 |
30 | help() # Welcome to Python 3.6's help utility!
31 |
32 | keywords # lists all keywords
33 | symbols # lists all symbols
34 | topics # lists all help topics
35 | modules # list all modules
36 | builtins # lists all built-in functions and exceptions
37 |
38 | yield # describes the yield statement
39 | @ # describes decorators
40 | DEBUGGING # provides information on 'pdb' the python debugger
41 | random # provides information on the random standard library module
42 | print # provides information in the print built-in function
43 | ValueError # provides information on the ValueError exception
44 |
45 | # you don't have to enter the help utility to get help either, you can pass
46 | # the name of a function or module directly (this method doesn't work for
47 | # keywords, symbols or topics).
48 |
49 | help(print)
50 | help(ValueError)
51 | import random
52 | help(random)
53 |
54 | # you can also ask for specific help on a method or class such as:
55 |
56 | help(list.extend)
57 | help(str.translate)
58 | help(set.difference)
59 | help(datetime.datetime)
60 |
61 |
62 | # dir()
63 | # -----------------------------------------------------------------------------
64 | # The built-in dir function is an easy way to grab a list of all the attributes
65 | # available inside an object (i.e., its methods and simpler data items). It can
66 | # be called on any object that has attributes, including imported modules and
67 | # built-in types, as well as the name of a data type.
68 |
69 | import random
70 | dir(random)
71 | # [..., 'betavariate', 'choice', 'choices', 'expovariate', 'gammavariate',
72 | # 'gauss', 'getrandbits', 'getstate', 'lognormvariate', 'normalvariate',
73 | # 'paretovariate', 'randint', 'random', 'randrange', 'sample', 'seed',
74 | # 'setstate', 'shuffle', 'triangular', 'uniform', 'vonmisesvariate',
75 | # 'weibullvariate']
76 |
77 | # To find out what attributes are provided in objects of built-in types, run
78 | # dir on a literal or an existing instance of the desired type. For example,
79 | # to see list, string, dict attributes, you can pass empty objects:
80 |
81 | dir(list)
82 | # [..., 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop',
83 | # 'remove', 'reverse', 'sort']
84 | dir(str)
85 | # [..., 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith',
86 | # 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha',
87 | # 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable',
88 | # 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip',
89 | # 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust',
90 | # 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith',
91 | # 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']'
92 | dir(dict)
93 | # [..., 'clear', 'copy', 'fromkeys', 'get', 'items', 'keys', 'pop', 'popitem',
94 | # 'setdefault', 'update', 'values']
95 | dir(tuple)
96 | # [..., 'count', 'index']
97 | dir(set)
98 | # [..., 'add', 'clear', 'copy', 'difference', 'difference_update', 'discard',
99 | # 'intersection', 'intersection_update', 'isdisjoint', 'issubset', 'issuperset',
100 | # 'pop', 'remove', 'symmetric_difference', 'symmetric_difference_update',
101 | # 'union', 'update']
102 |
103 |
104 | # Docstrings
105 | # -----------------------------------------------------------------------------
106 | # Builtins, modules and more have their own docstrings, which can also provide
107 | # information. For example:
108 |
109 | print(print.__doc__)
110 | import random
111 | print(random.__doc__)
112 | print(random.choice.__doc__)
113 |
114 |
115 | # HTML PyDoc
116 | # -----------------------------------------------------------------------------
117 | # Another way to view help similar to the help() and docstrings is to use
118 | # the built-in PyDoc HTML by running this command in terminal:
119 |
120 | # python3 -m pydoc -b
121 |
122 | # The interesting thing about this is, it will include any python modules
123 | # (.py files) it finds from the current directory you were in when you
124 | # launched it. It's actually pretty great!
125 |
126 |
127 | # View the source code
128 | # -----------------------------------------------------------------------------
129 | # If you want to take a look at the actual file to read the comments and
130 | # docstring there, you can use the __file__ magic method to show you the
131 | # path to where this module lives:
132 |
133 | import os
134 | print(os.__file__)
135 | # /Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/os.py
136 |
--------------------------------------------------------------------------------
/rounding_example.py:
--------------------------------------------------------------------------------
1 | '''Rounding Issue with Floats and Solutions'''
2 |
3 |
4 | # Floating point numbers are subject to rounding errors as they convert between
5 | # binary and decimal. One solution is to use the decimal module that comes with
6 | # python. The decimal module provides support for fast correctly-rounded
7 | # decimal floating point arithmetic. It offers several advantages over the
8 | # float datatype but will require some heavy investigation.
9 |
10 | # The other method of dealing with this rounding error is to work strictly
11 | # with integers instead of floats. This would mean multiplying by 100 and
12 | # essentially doing all calculations as pennies, then dividing by 100 to
13 | # convert back to dollars for the final show_balance.
14 |
15 |
16 | # Example 1: floats
17 | # -----------------------------------------------------------------------------
18 |
19 | class Account1():
20 |
21 | def __init__(self, name: str, opening_balance: float=0.0):
22 | self.name = name
23 | self._balance = opening_balance
24 | print('Account created for {}'.format(self.name))
25 | self.show_balance()
26 |
27 | def deposit(self, amount: float):
28 | if amount > 0.0:
29 | self._balance += amount
30 | print('{} deposited'.format(amount))
31 | return self._balance
32 |
33 | def withdraw(self, amount: float):
34 | if 0 < amount <= self._balance:
35 | self._balance -= amount
36 | print('{} withdrawn'.format(amount))
37 | return amount
38 | else:
39 | print('Amount must be greater than 0 and not exceed balance')
40 | return 0.0
41 |
42 | def show_balance(self):
43 | print('Balance on account {} is {}'.format(self.name, self._balance))
44 |
45 | # testing:
46 | if __name__ == '__main__':
47 | rick = Account1('Rick')
48 | rick.deposit(100.10)
49 | rick.deposit(499.10)
50 | rick.deposit(55.10)
51 | rick.withdraw(80.00)
52 | rick.show_balance()
53 |
54 | # Account created for Rick
55 | # Balance on account Rick is 0.0
56 | # 100.1 deposited
57 | # 499.1 deposited
58 | # 55.1 deposited
59 | # 80.0 withdrawn
60 | # Balance on account Rick is 574.3000000000001
61 |
62 |
63 | # Example 2: decimal module
64 | # -----------------------------------------------------------------------------
65 |
66 | from decimal import *
67 |
68 | class Account2():
69 | # class constant, accessible without creating an instance:
70 | _qb = Decimal('0.00')
71 |
72 | def __init__(self, name: str, opening_balance: float=0.0):
73 | self.name = name
74 | self._balance = Decimal(opening_balance).quantize(Account2._qb)
75 | print("Account created for {}. ".format(self.name))
76 | self.show_balance()
77 |
78 | def deposit(self, amount: float):
79 | decimal_amount = Decimal(amount).quantize(Account2._qb)
80 | if decimal_amount > Account2._qb:
81 | self._balance = self._balance + decimal_amount
82 | print("{} deposited".format(decimal_amount))
83 | return self._balance
84 |
85 | def withdraw(self, amount: float):
86 | decimal_amount = Decimal(amount).quantize(Account2._qb)
87 | if Account2._qb < decimal_amount <= self._balance:
88 | self._balance = self._balance - decimal_amount
89 | print("{} withdrawn".format(decimal_amount))
90 | return decimal_amount
91 | else:
92 | print('Amount must be greater than 0 and not exceed balance')
93 | return Account2._qb
94 |
95 | def show_balance(self):
96 | print("Balance on account {} is {}".format(self.name, self._balance))
97 |
98 | #testing:
99 | if __name__ == '__main__':
100 | rick = Account2('Morty')
101 | rick.deposit(100.10)
102 | rick.deposit(499.10)
103 | rick.deposit(55.10)
104 | rick.withdraw(80.00)
105 | rick.show_balance()
106 |
107 | # Account created for Morty.
108 | # Balance on account Morty is 0.00
109 | # 100.10 deposited
110 | # 499.10 deposited
111 | # 55.10 deposited
112 | # 80.00 withdrawn
113 | # Balance on account Morty is 574.30
114 |
115 |
116 | # Example 3: use integers
117 | # -----------------------------------------------------------------------------
118 |
119 | class Account3():
120 |
121 | def __init__(self, name: str, opening_balance: int=0):
122 | self.name = name
123 | self._balance = opening_balance
124 | print('Account created for {}'.format(self.name))
125 | self.show_balance()
126 |
127 | def deposit(self, amount: int):
128 | if amount > 0.0:
129 | self._balance += amount
130 | print('{:.2f} deposited'.format(amount / 100))
131 | return self._balance / 100
132 |
133 | def withdraw(self, amount: int):
134 | if 0 < amount <= self._balance:
135 | self._balance -= amount
136 | print('{:.2f} withdrawn'.format(amount / 100))
137 | return amount / 100
138 | else:
139 | print('Amount must be greater than 0 and not exceed balance')
140 | return 0.0
141 |
142 | def show_balance(self):
143 | print('Balance on account {} is {:.2f}'.format(
144 | self.name, self._balance / 100))
145 |
146 | # testing:
147 | if __name__ == '__main__':
148 | rick = Account3('Bob')
149 | rick.deposit(10010)
150 | rick.deposit(49910)
151 | rick.deposit(5510)
152 | rick.withdraw(8000)
153 | rick.show_balance()
154 |
155 | # Account created for Bob
156 | # Balance on account Bob is 0.00
157 | # 100.10 deposited
158 | # 499.10 deposited
159 | # 55.10 deposited
160 | # 80.00 withdrawn
161 | # Balance on account Bob is 574.30
162 |
--------------------------------------------------------------------------------
/sqlite3_example2.py:
--------------------------------------------------------------------------------
1 | '''sqlite3 Example'''
2 |
3 |
4 | # This is a modified version of sqlite3_example1.py. In continuing to explore
5 | # ways of storing and retrieving both UTC and local time, this example includes
6 | # a column in the history table that contains a pickled datetime object which
7 | # is the local time zone (PDT). This pickled object can then be unpickled and
8 | # displayed later. This whole thing is probably overkill for most situations
9 | # but may prove useful as an example sometime.
10 |
11 | import sqlite3
12 | import datetime
13 | import pytz
14 | import pickle # <-- added
15 |
16 | db = sqlite3.connect('data/accounts2.sqlite')
17 | db.execute('''CREATE TABLE IF NOT EXISTS accounts
18 | (name TEXT PRIMARY KEY NOT NULL,
19 | balance INTEGER NOT NULL)''')
20 | # added timezone column to the history table:
21 | db.execute('''CREATE TABLE IF NOT EXISTS history
22 | (time TIMESTAMP NOT NULL,
23 | account TEXT NOT NULL,
24 | amount INTEGER NOT NULL,
25 | timezone INTEGER NOT NULL,
26 | PRIMARY KEY (time, account))''')
27 |
28 |
29 | class Account():
30 |
31 | @staticmethod
32 | def _current_time():
33 | # changed this to return both utc time and local time zone:
34 | utc_time = pytz.utc.localize(datetime.datetime.utcnow())
35 | local_time = utc_time.astimezone()
36 | timezone = local_time.tzinfo
37 | return utc_time, timezone # <-- returns a tuple
38 |
39 | def __init__(self, name: str, opening_balance: int=0):
40 | select_query = "SELECT name, balance FROM accounts WHERE name = ?"
41 | cursor = db.execute(select_query, (name,))
42 | row = cursor.fetchone()
43 | if row:
44 | self.name, self._balance = row
45 | print('Retrieved record for {}'.format(self.name))
46 | else:
47 | self.name = name
48 | self._balance = opening_balance
49 | insert_query = "INSERT INTO accounts VALUES(?, ?)"
50 | cursor.execute(insert_query, (name, opening_balance))
51 | cursor.connection.commit()
52 | print('Account created for {}'.format(self.name))
53 | self.show_balance()
54 |
55 | def _save_update(self, amount):
56 | new_balance = self._balance + amount
57 | time, timezone = Account._current_time() # <-- unpack the tuple
58 | pickled_timezone = pickle.dumps(timezone) # <-- pickle the time zone
59 | try:
60 | db.execute("UPDATE accounts SET balance = ? WHERE name = ?",
61 | (new_balance, self.name))
62 | # add the pickled_timezone to the update:
63 | db.execute("INSERT INTO history VALUES(?, ?, ?, ?)",
64 | (time, self.name, amount, pickled_timezone))
65 | except sqlite3.Error:
66 | db.rollback()
67 | else:
68 | db.commit()
69 | self._balance = new_balance
70 |
71 | def deposit(self, amount: int):
72 | if amount > 0.0:
73 | self._save_update(amount)
74 | print('{:.2f} deposited - {}'.format(amount/100, self.name))
75 | return self._balance/100
76 |
77 | def withdraw(self, amount: int):
78 | if 0 < amount <= self._balance:
79 | self._save_update(-amount)
80 | print('{:.2f} withdrawn - {}'.format(amount/100, self.name))
81 | return amount/100
82 | else:
83 | print('Amount must be greater than 0 and not exceed balance')
84 | return 0.0
85 |
86 | def show_balance(self):
87 | print('Balance for {} is {:.2f}'.format(self.name, self._balance/100))
88 |
89 |
90 | # Testing
91 | # -----------------------------------------------------------------------------
92 |
93 | if __name__ == '__main__':
94 | rick = Account('Rick')
95 | morty = Account('Morty', 50000)
96 | pingpong = Account('Ping Pong', 10000)
97 | boktoktok = Account('Boktoktok', 2000)
98 | zed = Account('Zed', 900000)
99 |
100 | rick.deposit(10010)
101 | morty.withdraw(1000)
102 | zed.deposit(99900)
103 |
104 | db.close()
105 |
106 | print('-' * 75)
107 |
108 |
109 | # Get the pickled timezone
110 | # -----------------------------------------------------------------------------
111 |
112 | db = sqlite3.connect('data/accounts2.sqlite', detect_types=sqlite3.PARSE_DECLTYPES)
113 |
114 | for row in db.execute("SELECT * FROM history"):
115 | utc_time = row[0]
116 | pickled_timezone = row[3]
117 | timezone = pickle.loads(pickled_timezone)
118 | local_time = pytz.utc.localize(utc_time).astimezone(timezone)
119 | print("{}\t{}\t{}".format(utc_time, local_time, local_time.tzinfo))
120 |
121 | # 2017-12-01 18:45:25.093112 2017-12-01 10:45:25.093112-08:00 PST
122 | # 2017-12-01 18:45:25.095254 2017-12-01 10:45:25.095254-08:00 PST
123 |
--------------------------------------------------------------------------------
/template.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | '''Docstring Summary Line, followed by a space.
4 |
5 | Followed by the extended description of the module. This may include
6 | special notes on structure and usage as well as include brief information
7 | on the modules Classes, Functions and variables.
8 | '''
9 |
10 | import datetime as dt
11 | from random import choice
12 |
13 |
14 | __author__ = "Jessica Rush"
15 | __copyright__ = "Copyright 2017, cyan red"
16 | __credits__ = ["Scott Volk", "Someone Else"]
17 | __license__ = "GPL"
18 | __version__ = "1.0.1"
19 | __maintainer__ = "Jessica Rush"
20 | __email__ = "jesskrush@me.com"
21 | __status__ = "Production"
22 |
23 |
24 | print('template finished')
25 |
26 | # Explanation: The above is a recommended example source code file header.
27 | # The main things to note here:
28 |
29 | # 1. The first line of each file should be #!/usr/bin/env python (or the path
30 | # to wherever your installation is... see which python3 for your path).
31 | # This makes it possible to run the file as a script invoking the
32 | # interpreter implicitly, (basically, just type $ ./template.py in the
33 | # command line instead of $ python3 template.py). Note that the file
34 | # permissions need to allow for the file to be executeable. For example,
35 | # the command $ sudo chmod 744 template.py, would give the file the
36 | # permissions: -rwxr--r--
37 |
38 | # 2. Next should be the docstring with a description. If the description is
39 | # long, the first line should be a short summary that makes sense on its
40 | # own, separated from the rest by a newline.
41 |
42 | # 3. Third should be all the import statements. Standard library first, then
43 | # third-party libraries, then your own modules.
44 |
45 | # 4. OPTIONAL: Authorship information. Note that many feel this information
46 | # should be kept out of the source file and kept in its own file(s) such
47 | # as AUTHORS and LICENSE. Status should typically be one of "Prototype",
48 | # "Development", or "Production". More information can be found here:
49 | # http://epydoc.sourceforge.net/manual-fields.html#module-metadata-variables
50 |
--------------------------------------------------------------------------------
/timezones.py:
--------------------------------------------------------------------------------
1 | '''Timezones'''
2 |
3 |
4 | # A reminder: it's best to avoid working with timezones. Instead, the best
5 | # practice would be to convert any times/dates to UTC at the start, do all
6 | # your processing in UTC and then convert back to timezones only if you have
7 | # to at the end for the user.
8 |
9 | # As it turns out, the web browser knows the user's timezone, and exposes it
10 | # through the standard date and time JavaScript APIs. A good way of utilizing
11 | # this is to let the conversion from UTC to a local timezone happen in the
12 | # web client using JavaScript. There is a small open-source JavaScript library
13 | # called moment.js that handles this very well. Though not demonstrated in this
14 | # file, note that there is a Flask extension called Flask-Moment that makes it
15 | # easy to incorporate moment.js into your Flask app.
16 |
17 |
18 | # pytz module
19 | # -----------------------------------------------------------------------------
20 | import datetime
21 | import pytz
22 |
23 | # FYI pytz pulls timezone information from this database:
24 | # https://www.iana.org/time-zones
25 |
26 | # see all timezones:
27 | for x in pytz.all_timezones:
28 | print(x)
29 |
30 | # see all country codes:
31 | for x in sorted(pytz.country_names):
32 | print(x, ':', pytz.country_names[x])
33 |
34 | # see all country names:
35 | for x in sorted(pytz.country_names):
36 | print(f'{x}: {pytz.country_names[x]}: {pytz.country_timezones.get(x)}')
37 |
38 | # see names, zones and their times:
39 | for x in sorted(pytz.country_names):
40 | print(f'{x}: {pytz.country_names[x]}')
41 | if x in pytz.country_timezones:
42 | for zone in sorted(pytz.country_timezones[x]):
43 | tz_to_display = pytz.timezone(zone)
44 | local_time = datetime.datetime.now(tz=tz_to_display)
45 | print(f'\t{zone}: {local_time}')
46 | else:
47 | print('\tNo timezone defined')
48 |
49 |
50 | # pytz example
51 | # -----------------------------------------------------------------------------
52 | import datetime
53 | import pytz
54 |
55 |
56 | country = "Europe/Moscow"
57 | tz = pytz.timezone(country)
58 | world_time = datetime.datetime.now(tz=tz)
59 |
60 | print(f'UTC is {datetime.datetime.utcnow()}')
61 | # UTC is 2018-03-28 19:39:09.028962
62 |
63 | print(f'The time in {country} is {world_time}')
64 | # The time in Europe/Moscow is 2018-03-28 22:39:09.028943+03:00
65 |
66 | print(f'In {country} it is {world_time.strftime("%A %x %X")} - {world_time.tzname()}')
67 | # In Europe/Moscow it is Wednesday 03/28/18 22:39:09 - MSK
68 |
69 |
70 | # convert a naive datetime to an aware datetime
71 | # -----------------------------------------------------------------------------
72 | import datetime
73 | import pytz
74 |
75 |
76 | naive_local_time = datetime.datetime.now()
77 | naive_utc_time = datetime.datetime.utcnow()
78 |
79 | print(f'Naive local time: {naive_local_time}')
80 | print(f'Naive UTC: {naive_utc_time}')
81 |
82 | # Naive local time: 2018-03-28 12:39:09.029068
83 | # Naive UTC: 2018-03-28 19:39:09.0290701
84 |
85 | # When these next two print you can tell they are aware because they now
86 | # include an offset at the end. Both will show the same time zone and same
87 | # offset (+00:00, UTC) because the naive datetimes we supplied to it don't
88 | # carry that information. The third example shows how to get the correct local
89 | # offset and time zone:
90 |
91 | aware_local_time = pytz.utc.localize(naive_local_time)
92 | aware_utc_time = pytz.utc.localize(naive_utc_time)
93 | aware_local_time_zone = pytz.utc.localize(naive_utc_time).astimezone()
94 |
95 | print(f'Aware local time: {aware_local_time} - '
96 | f'time zone: {aware_local_time.tzinfo}')
97 | # Aware local time: 2018-03-28 12:39:09.029068+00:00 - time zone: UTC
98 |
99 | print(f'Aware UTC: {aware_utc_time} - '
100 | f'time zone: {aware_utc_time.tzinfo}')
101 | # Aware UTC: 2018-03-28 19:39:09.029070+00:00 - time zone: UTC
102 |
103 | print(f'Aware local time: {aware_local_time_zone} - '
104 | f'time zone: {aware_local_time_zone.tzinfo}')
105 | # Aware local time: 2018-03-28 12:39:09.029070-07:00 - time zone: PDT
106 |
107 |
108 | # date in a timezone from epoch
109 | # -----------------------------------------------------------------------------
110 | # Use time stamps (seconds since the epoch) to convert to actual date.
111 | # For this example we'll be supplying the timezone since an epoch number could
112 | # be from anywhere. This particular timestamp is the hour before DST in the UK
113 | # on October 25, 2015. You will see the difference before and after the DST in
114 | # the offset.
115 |
116 | s = 1445733000
117 | t = s + (60 * 60)
118 |
119 | tz = pytz.timezone("Canada/Pacific")
120 | dt1 = pytz.utc.localize(datetime.datetime.utcfromtimestamp(s)).astimezone(tz)
121 | dt2 = pytz.utc.localize(datetime.datetime.utcfromtimestamp(t)).astimezone(tz)
122 |
123 | print(f'{s} seconds since epoch is {dt1}')
124 | print(f'{t} seconds since epoch is {dt2}')
125 |
126 | # 1445733000 seconds since epoch is 2015-10-24 17:30:00-07:00
127 | # 1445736600 seconds since epoch is 2015-10-24 18:30:00-07:00
128 |
--------------------------------------------------------------------------------
/timezones_example.py:
--------------------------------------------------------------------------------
1 | '''Timezones Example'''
2 |
3 |
4 | # A program that allows a user to choose one time zones from a list.
5 | # The program will then display the time in that timezone,
6 | # as well as local time & UTC time.
7 |
8 | import datetime
9 | import pytz
10 |
11 |
12 | # References
13 | # -----------------------------------------------------------------------------
14 | # print all timezones:
15 | for x in pytz.all_timezones:
16 | print(x)
17 |
18 | # print all country names, timezones and their times:
19 | for x in sorted(pytz.country_names):
20 | print("{}: {}".format(x, pytz.country_names[x]))
21 | if x in pytz.country_timezones:
22 | for zone in sorted(pytz.country_timezones[x]):
23 | tz_to_display = pytz.timezone(zone)
24 | local_time = datetime.datetime.now(tz=tz_to_display)
25 | print("\t{}: {}:".format(zone, local_time))
26 | else:
27 | print("\tNo timezone defined")
28 |
29 |
30 | # Program
31 | # -----------------------------------------------------------------------------
32 |
33 | timezones = {'vancouver': 'America/Vancouver',
34 | 'luxembourg': 'Europe/Luxembourg',
35 | 'hong kong': 'Hongkong',
36 | 'switzerland': 'Europe/Zurich',
37 | 'shanghai': 'Asia/Shanghai',
38 | 'cuba': 'America/Havana',
39 | 'berlin': 'Europe/Berlin',
40 | 'turks & caicos': 'America/Grand_Turk',
41 | 'singapore': 'Singapore'}
42 |
43 | for zone in sorted(timezones):
44 | print(zone.title())
45 |
46 | while True:
47 | selection = input('Choose a q (q to quit): ').lower()
48 | if selection == 'q':
49 | break
50 | if selection in timezones:
51 | country = timezones[selection]
52 | tz_to_display = pytz.timezone(country)
53 | world_time = datetime.datetime.now(tz=tz_to_display)
54 |
55 | # unformatted output:
56 | # print("{} time is: {}".format(selection.title(), world_time))
57 | # print("Local time is: {}".format(datetime.datetime.now()))
58 | # print("UTC is: {}".format(datetime.datetime.utcnow()))
59 |
60 | # fancier output:
61 | world = '{} time is:'.format(selection.title())
62 | local = 'Local time is:'
63 | utc = 'UTC time is:'
64 | print("{:24} {} {}".format(
65 | world, world_time.strftime('%A %x %X'), world_time.tzname()))
66 | print("{:24} {}".format(
67 | local, datetime.datetime.now().strftime('%A %x %X')))
68 | print("{:24} {}".format(
69 | utc, datetime.datetime.utcnow().strftime('%A %x %X')))
70 | else:
71 | print("That's not in my list")
72 |
--------------------------------------------------------------------------------
/tkinter_example.py:
--------------------------------------------------------------------------------
1 | '''tkinter example - (NOT a functioning calculator)'''
2 |
3 |
4 | import tkinter as tk
5 | from tkinter import ttk
6 |
7 |
8 | def click(key):
9 | '''dummy function for testing purposes only'''
10 | if (key == 'C') or (key == 'CE'):
11 | entry.delete(0, tk.END)
12 | else:
13 | entry.insert(tk.END, key)
14 |
15 |
16 | # Button text is stored as a list of row lists. The list items here are tuples,
17 | # where the second value is being used as the colspan in the code below:
18 | keys = [[('C', 2), ('CE', 2)],
19 | [('7', 1), ('8', 1), ('9', 1), ('+', 1)],
20 | [('4', 1), ('5', 1), ('6', 1), ('-', 1)],
21 | [('1', 1), ('2', 1), ('3', 1), ('*', 1)],
22 | [('0', 1), ('=', 2), ('/', 1)],]
23 |
24 | # Using a variable for padding, since it's also used to calculate window size:
25 | mainWindowPadding = 8
26 |
27 | # Main window setup:
28 | mainWindow = tk.Tk()
29 | mainWindow.title("Calculator")
30 | mainWindow.geometry('50x50-25-25')
31 | mainWindow['padx'] = mainWindowPadding
32 |
33 | # example style some ttk elements:
34 | style = ttk.Style()
35 |
36 | # A bug caused by the 'aqua' ttk style on Mac OSX makes it so that some
37 | # elements won't drop the light gray background color. Classic should fix it:
38 | style.theme_use('classic')
39 | style.configure("test.TLabel", foreground="magenta", background="yellow")
40 |
41 | # Example ttk window label:
42 | label = ttk.Label(mainWindow, text='tkinter example', padding=(38,5,38,5),
43 | style='test.TLabel')
44 | label.grid(row=0, column=0)
45 |
46 | # Result field:
47 | # A "width" configuration option may be specified to provide the number of
48 | # characters wide the entry should be.
49 | entry = tk.Entry(mainWindow)
50 | entry.grid(row=1, column=0, sticky='nsew')
51 | entry.config(width=10)
52 |
53 | # Key pad:
54 | keyPad = tk.Frame(mainWindow)
55 | keyPad.grid(row=2, column=0, sticky='nsew')
56 |
57 | # padx and pady are intended to add external padding - the value can be a
58 | # number or a tuple (5, 15) for separate left, right - top, bottom values.
59 | # ipadx and ipady are intended to add internal padding - the value can only
60 | # be a number, not a tuple. These don't appear to work consistently. In the
61 | # example below both ipady and pady give the same result:
62 |
63 | row = 0
64 | for keyRow in keys:
65 | col = 0
66 | for key in keyRow:
67 | cmd = lambda x=key[0]: click(x)
68 | tk.Button(keyPad, text=key[0], command=cmd).grid(
69 | row=row, column=col, columnspan=key[1], sticky='nsew', ipadx=5)
70 | col += key[1]
71 | row += 1
72 |
73 | # Set the minsize(), and a maxsize() of the window using the width and height
74 | # of the keyPad element - .winfo_height() and winfo_width() methods.
75 | # This won't work unless we force the window to draw the widgets first by
76 | # calling its .update() method:
77 |
78 | mainWindow.update()
79 |
80 | mainWindow.minsize((keyPad.winfo_width() + mainWindowPadding * 2),
81 | (entry.winfo_height() + keyPad.winfo_height() + label.winfo_height()
82 | + mainWindowPadding))
83 |
84 | mainWindow.maxsize((keyPad.winfo_width() + mainWindowPadding * 2),
85 | (entry.winfo_height() + keyPad.winfo_height() + label.winfo_height()
86 | + mainWindowPadding))
87 |
88 | mainWindow.mainloop()
89 |
--------------------------------------------------------------------------------
/virtual_environments.md:
--------------------------------------------------------------------------------
1 | # Virtual Environments
2 |
3 | ## Table of contents
4 |
5 |
6 |
7 | - [Introduction](#introduction)
8 | - [Create a virtual environment](#create-a-virtual-environment)
9 | - [Run your program in the virtual environment](#run-your-program-in-the-virtual-environment)
10 | - [Keep track of requirements](#keep-track-of-requirements)
11 |
12 |
13 |
14 | ## Introduction
15 |
16 | A Virtual Environment, put simply, is an isolated working copy of Python that allows you to work on a specific project without affecting any other projects. It creates a directory which contains all the necessary executables to use the packages that a Python project would need.
17 |
18 | The basic problem being addressed is one of dependencies and versions, and indirectly permissions. Imagine you have an application that needs version 1 of Library-xyz, but another application requires version 2. How can you use both these applications? It’s easy to end up in a situation where you unintentionally upgrade an application that shouldn’t be.
19 |
20 | More generally, what if you want to install an application and leave it be? If an application works, any change in its libraries or the versions of those libraries can break the application. Also, what if you can’t install packages into the global site-packages directory? For instance, on a shared host.
21 |
22 | In these cases, venv (standard library) or virtualenv (independent library) can help. Both create an environment that has its own installation directories, that don’t share libraries with other virtual environments (and optionally don’t access the globally installed libraries either).
23 |
24 |
25 |
26 |
27 | ## Create a virtual environment
28 |
29 | To create a virtual environment, navigate to your project directory in the command line and enter the following. Note: the *first* 'venv' is the name of the module (I'm choosing to use the one from Python's standard library), the *second* 'venv' is the directory name for all the environment files... call it whatever you want:
30 |
31 | ```
32 | $ python -m venv venv
33 | ```
34 |
35 | Next, install packages in the virtual environment. There are two ways to do this. The first method, from the same project directory where venv lives:
36 |
37 | ```
38 | $ venv/bin/pip install flask
39 | ```
40 |
41 | Alternatively, you can *activate* your virtual environment first, then pip install as you would normally:
42 |
43 | ```
44 | $ source venv/bin/activate
45 | (venv) $ pip install flask
46 | ```
47 |
48 | You should see the name of your environment `(venv)` at the start of the command line prompt. While in the activated state, you can pip install as you normally would (without the preceding venv/bin/ as above).
49 |
50 |
51 | ## Run your program in the virtual environment
52 |
53 | Again, you can do one of two things. First, the long way:
54 |
55 | ```
56 | $ venv/bin/python myscript.py
57 | ```
58 |
59 | or, you can activate your environment as above:
60 |
61 | ```
62 | $ source venv/bin/activate
63 | (venv) $ python myscript.py
64 | ```
65 |
66 | When you're finished working in the project, deactivate the environment:
67 |
68 | ```
69 | (venv) $ deactivate
70 | ```
71 |
72 | ## Keep track of requirements
73 |
74 | Depending on which method you prefer, do one of the following:
75 |
76 | ```
77 | $ venv/bin/pip freeze > requirements.txt
78 | (venv) $ pip freeze > requirements.txt
79 | ```
80 |
81 | See also: [package_management.py](https://github.com/jessicarush/python-examples/blob/master/package_management.py)
82 |
--------------------------------------------------------------------------------
/web_scraping.py:
--------------------------------------------------------------------------------
1 | '''Web Automation: Scraping'''
2 |
3 |
4 | # The webbrowser Module
5 | # -----------------------------------------------------------------------------
6 |
7 | import webbrowser
8 |
9 | url = "http://www.python.org/"
10 |
11 | webbrowser.open(url)
12 |
13 | # to open in a new window:
14 | webbrowser.open_new(url)
15 |
16 | # to open in a new tab (some browsers do this already via their own prefs):
17 | webbrowser.open_new_tab(url)
18 |
19 |
20 | # Crawl and Scrape
21 | # -----------------------------------------------------------------------------
22 | # Sometimes, you might want a little bit of information available only in HTML
23 | # pages, surrounded by ads and extraneous content. An automated web fetcher
24 | # (called a crawler or spider) retrieves content from the remote web servers,
25 | # and a scraper parses the content to find the needle in the haystack.
26 |
27 | # If you need an industrial-strength combined crawler and scraper, Scrapy is
28 | # worth downloading: $ pip install scrapy
29 |
30 | # Scrapy is a framework, not a module. It does more, but it's more complex to
31 | # set up. Learn more at: https://scrapy.org
32 |
33 |
34 | # Scrape with BeautifulSoup - basic parsing example
35 | # -----------------------------------------------------------------------------
36 | # If you already have the HTML data from a website and just want to extract
37 | # from it, BeautifulSoup is a good choice. HTML parsing is a headache because
38 | # much of the HTML on public web pages is technically invalid: unclosed tags,
39 | # incorrect nesting, and other complications.
40 |
41 | # $ pip install beautifulsoup4
42 |
43 | import requests
44 | from bs4 import BeautifulSoup as soup
45 |
46 |
47 | r = requests.get('http://pythonhow.com/example.html')
48 | c = r.content # the entire source code
49 | s = soup(c, 'html.parser') # feed the content to the bs4 parser
50 | a = s.find('div',{'class': 'cities'}) # returns the first div
51 | a = s.find_all('div',{'class': 'cities'}) # returns a list of all divs
52 |
53 | # print(s.prettify)
54 |
55 | print(type(r)) #
56 | print(type(c)) #
57 | print(type(s)) #
58 | print(type(a)) #
59 | print(type(a[2])) #
60 | print(a) # prints all the divs and their contents
61 | print(a[2]) # prints the 3rd div and its contents
62 | print(a[0].find_all('h2')) # list of all the h2 tags from the 1st div
63 | print(a[0].find_all('h2')[0]) # just the 1st h2
64 | print(a[0].find_all('h2')[0].text) # just the text inside the h2 tag
65 |
66 | for item in a:
67 | print(item.find_all('h2'))
68 | # [London
]
69 | # [Paris
]
70 | # [Tokyo
]
71 |
72 | for item in a:
73 | print(item.find_all('h2')[0].text)
74 | # London
75 | # Paris
76 | # Tokyo
77 |
78 |
79 | # Scrape with BeautifulSoup - links example
80 | # -----------------------------------------------------------------------------
81 | # The following example uses it to get all the links from a web page.
82 | # A function get_links() will do most of the work, and a main program to get
83 | # one or more URLs as command-line arguments.
84 |
85 | import requests
86 | from bs4 import BeautifulSoup as soup
87 |
88 |
89 | def get_links(url):
90 | result = requests.get(url)
91 | page = result.text
92 | doc = soup(page, 'html.parser')
93 | links = [element.get('href') for element in doc.find_all('a')]
94 | return links
95 |
96 | if __name__ == '__main__':
97 | import sys
98 | for url in sys.argv[1:]:
99 | print ('Links in', url)
100 | for num, link in enumerate(get_links(url), start=1):
101 | print(num, link)
102 | print()
103 |
104 | # The 'a' and 'href' represent the literal HTML:
105 |
106 | # The above can be saved as a program and run like so:
107 | # python3 getlinks.py http://python.org
108 |
--------------------------------------------------------------------------------
/while_loops.py:
--------------------------------------------------------------------------------
1 | '''While loops, break and continue'''
2 |
3 |
4 | # while is a looping mechanism that's used with if, elif, else and try. A while
5 | # loop will loop forever unless you, break, continue, pass or return something.
6 | # break is useful when you want to terminate the loop early if some condition
7 | # is met. continue is for when you want to skip past an iteration to the next.
8 |
9 | x = 5
10 | while x > 0:
11 | x -= 1
12 | if x == 2:
13 | break
14 | print(x)
15 | # 4
16 | # 3
17 |
18 | x = 5
19 | while x > 0:
20 | x -= 1
21 | if x == 2:
22 | continue
23 | print(x)
24 | # 4
25 | # 3
26 | # 1
27 | # 0
28 |
29 |
30 | # Example using if, elif, else, break and continue
31 | # -----------------------------------------------------------------------------
32 |
33 | import random
34 |
35 | print('Guess a number between 1 and 10 (0 to quit):')
36 |
37 | answer = random.randint(1, 9)
38 |
39 | while True:
40 | guess = (int(input('> ')))
41 | if guess != answer:
42 | if guess == 0:
43 | print('bye')
44 | break
45 | elif guess > answer:
46 | print('No, lower')
47 | continue
48 | else:
49 | print('No, higher')
50 | continue
51 | else:
52 | print('You guessed it!')
53 | break
54 |
55 |
56 | # Example using if, try, break, continue
57 | # -----------------------------------------------------------------------------
58 |
59 | def squared():
60 | while True:
61 | value = input('Enter an integer (q to quit): ')
62 | if value == 'q':
63 | break
64 | try:
65 | number = int(value)
66 | except ValueError:
67 | print("That's not an integer.")
68 | continue
69 | number = int(value)
70 | print(number, 'squared is', number * number)
71 |
72 | squared()
73 |
74 |
75 | # Example using try and return
76 | # -----------------------------------------------------------------------------
77 |
78 | print('Enter two numbers.')
79 |
80 | def get_inputs(arg):
81 | while True:
82 | try:
83 | x = input('{} number: '.format(arg))
84 | x = int(x)
85 | return x
86 | except:
87 | print('I need an integer.')
88 |
89 | a = get_inputs('first')
90 | b = get_inputs('second')
91 |
92 | print('{} * {} = {}'.format(a, b, a * b))
93 |
94 |
95 | # A slightly different approach
96 | # -----------------------------------------------------------------------------
97 | # A 'flag' variable is a great way of signaling to a while loop when you have
98 | # many things that could/should end the loop. Using a flag variable, our loop
99 | # only has to check one condition.
100 |
101 | print('Kilograms to Pounds converter.')
102 | prompt = 'Enter kilograms (q to quit): '
103 | KILO_POUNDS = 2.20462
104 | active = True # this is a flag variable!
105 |
106 | while active:
107 | value = input(prompt)
108 | if value == 'q':
109 | active = False
110 | else:
111 | try:
112 | new_value = int(value) * KILO_POUNDS
113 | print(value, 'kilograms is', new_value, 'pounds')
114 | except:
115 | print("I need a number or 'q' to quit: ")
116 |
117 |
118 | # While Loops with Lists & Dicts
119 | # -----------------------------------------------------------------------------
120 | # A for loop is effective for iterating through a list but apparently, "You
121 | # shouldn't modify a list inside a for loop because Python will have trouble
122 | # keeping track of the items in the list. To modify a list as you work through
123 | # it, use a while loop." Using a while loop allows you to better collect,
124 | # store and organize.
125 |
126 | unconfirmed_users = ['rick', 'morty', 'raja', 'bob']
127 | confirmed_users = []
128 |
129 | while unconfirmed_users:
130 | current_user = unconfirmed_users.pop()
131 | print('Magical verification of user: {}'.format(current_user.title()))
132 | confirmed_users.append(current_user)
133 |
134 | for user in confirmed_users:
135 | print('Confirmed user: {}'.format(user.title()))
136 |
137 |
138 | # Filling a dict with user input
139 | # -----------------------------------------------------------------------------
140 |
141 | shopping_list = {}
142 |
143 | while True:
144 | item = input('Item (q to quit): ')
145 | if item == 'q':
146 | break
147 | store = input('Store: ')
148 | if store in shopping_list:
149 | shopping_list[store].append(item)
150 | else:
151 | shopping_list[store] = [item]
152 |
153 | if shopping_list:
154 | print('Shopping list\n')
155 |
156 | for store, items, in shopping_list.items():
157 | print(store.title())
158 | for item in items:
159 | print('– ', item)
160 | print('-' * 25)
161 |
--------------------------------------------------------------------------------
/zip_function.py:
--------------------------------------------------------------------------------
1 | '''zip() Built-in Function'''
2 |
3 |
4 | # Iterating over multiple sequences
5 | # -----------------------------------------------------------------------------
6 | # the zip() function wraps two or more iterators in a lazy generator.
7 | # It yields a tuple containing the next value from each iterator.
8 |
9 | days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
10 | fruits = ['Apple', 'Banana', 'Pear']
11 | drinks = ['Tea', 'Juice', 'Wine']
12 | desserts = ['Ice cream', 'Cookies', 'Cake', 'Candy']
13 |
14 | for day, fruit, drink, dessert in zip(days, fruits, drinks, desserts):
15 | print(day.upper())
16 | print(f'– {fruit}, {drink}, {dessert}')
17 |
18 | # MONDAY
19 | # – Apple, Tea, Ice cream
20 | # TUESDAY
21 | # – Banana, Juice, Cookies
22 | # WEDNESDAY
23 | # – Pear, Wine, Cake
24 |
25 | # When using zip in this manner, it will stop iterating when it reaches the
26 | # end of the shortest list. If you want it to exhaust the longest list, use
27 | # zip_longest() from itertools:
28 |
29 | from itertools import zip_longest
30 |
31 | for day, fruit, drink, dessert in zip_longest(days, fruits, drinks, desserts):
32 | print(day.upper())
33 | print(f'– {fruit}, {drink}, {dessert}')
34 |
35 | # MONDAY
36 | # – Apple, Tea, Ice cream
37 | # TUESDAY
38 | # – Banana, Juice, Cookies
39 | # WEDNESDAY
40 | # – Pear, Wine, Cake
41 | # THURSDAY
42 | # – None, None, Candy
43 | # FRIDAY
44 | # – None, None, None
45 |
46 |
47 | # create a dictionary from two sequences
48 | # -----------------------------------------------------------------------------
49 |
50 | english = ['Monday', 'Tuesday', 'Wednesday', 'Thursday']
51 | french = ['Lundi', 'Mardi', 'Mecredi']
52 |
53 | e2f = dict(zip(english, french))
54 | f2e = dict(zip(french, english))
55 |
56 | print(e2f['Tuesday']) # Mardi
57 | print(f2e['Mardi']) # Tuesday
58 |
59 | # as above, zip will stop creating key/value pairs at the end of the shortest
60 | # list. In the example above, no key will be created for Thursday.
61 |
62 |
63 | # Another example
64 | # -----------------------------------------------------------------------------
65 |
66 | colours = ['Red', 'Cyan', 'Magenta', 'Orange']
67 | hexadecimal = ['FA200C', '0CD3FA', 'FF0D91', 'FF690D']
68 |
69 | colour_values = dict(zip(colours, hexadecimal))
70 |
71 | print(colour_values)
72 | # {'Red': 'FA200C', 'Cyan': '0CD3FA', 'Magenta': 'FF0D91', 'Orange': 'FF690D'}
73 |
74 | # NOTE that zip() behaves differently in Python 2. In version 2 it is not a
75 | # generator and can therefor use a lot of memory. In Python 2 use itertools
76 | # instead.
77 |
--------------------------------------------------------------------------------