Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31aef36ffd | ||
|
|
aef6a98f98 | ||
|
|
99e4fa3c79 | ||
|
|
f9cc52cc83 | ||
|
|
948996705e | ||
|
|
e09bd887b5 | ||
|
|
7358db6429 | ||
|
|
ec8a37af1c | ||
|
|
4e6a69c038 | ||
|
|
fbb0e61b04 | ||
|
|
715b83f929 | ||
|
|
2d90f4aa31 | ||
|
|
fd28fa3fde | ||
|
|
3696da7ae4 | ||
|
|
d60a9f538d | ||
|
|
20fa53960d | ||
|
|
d58ebc1ebe | ||
|
|
09b4bc8f5b | ||
|
|
f2b35db671 | ||
|
|
8014742933 |
3
.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
venv/
|
||||
site/
|
||||
site/
|
||||
videos/
|
||||
@@ -1,34 +1,34 @@
|
||||
variables:
|
||||
CI_PROJECT_DIR: "."
|
||||
CI_REGISTRY_IMAGE: hub.ducoterra.net/ducoterra/python-docs-2020
|
||||
DEPLOY: pythondocs2020
|
||||
# variables:
|
||||
# CI_PROJECT_DIR: "."
|
||||
# CI_REGISTRY_IMAGE: hub.ducoterra.net/ducoterra/python-docs-2020
|
||||
# DEPLOY: pythondocs2020
|
||||
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
# stages:
|
||||
# - build
|
||||
# - deploy
|
||||
|
||||
build:
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_TAG
|
||||
stage: build
|
||||
image:
|
||||
name: gcr.io/kaniko-project/executor:debug
|
||||
entrypoint: [""]
|
||||
script:
|
||||
- /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
|
||||
# build:
|
||||
# only:
|
||||
# variables:
|
||||
# - $CI_COMMIT_TAG
|
||||
# stage: build
|
||||
# image:
|
||||
# name: gcr.io/kaniko-project/executor:debug
|
||||
# entrypoint: [""]
|
||||
# script:
|
||||
# - /kaniko/executor --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_TAG
|
||||
|
||||
deploy:
|
||||
stage: deploy
|
||||
only:
|
||||
variables:
|
||||
- $CI_COMMIT_TAG
|
||||
image:
|
||||
name: debian:10
|
||||
entrypoint: [""]
|
||||
script:
|
||||
- apt -qq update >> /dev/null && apt -qq install -y curl gettext >> /dev/null
|
||||
- curl -o /usr/bin/kubectl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
|
||||
- chmod +x /usr/bin/kubectl
|
||||
- curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
|
||||
- helm upgrade --install $DEPLOY ./helm --set image=$CI_REGISTRY_IMAGE --set tag=$CI_COMMIT_TAG
|
||||
# deploy:
|
||||
# stage: deploy
|
||||
# only:
|
||||
# variables:
|
||||
# - $CI_COMMIT_TAG
|
||||
# image:
|
||||
# name: debian:10
|
||||
# entrypoint: [""]
|
||||
# script:
|
||||
# - apt -qq update >> /dev/null && apt -qq install -y curl gettext >> /dev/null
|
||||
# - curl -o /usr/bin/kubectl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
|
||||
# - chmod +x /usr/bin/kubectl
|
||||
# - curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
|
||||
# - helm upgrade --install $DEPLOY ./helm --set image=$CI_REGISTRY_IMAGE --set tag=$CI_COMMIT_TAG
|
||||
|
||||
13
README.md
@@ -1,5 +1,18 @@
|
||||
# Docs
|
||||
|
||||
Converting mov to gif:
|
||||
|
||||
```bash
|
||||
ffmpeg -i in.mov -filter:v "setpts=0.5*PTS" out.gif
|
||||
```
|
||||
|
||||
Converting mkv to mp4 with 20Mbit bitrate
|
||||
|
||||
```bash
|
||||
ffmpeg -i in.mkv -b:v 20M out.mov
|
||||
```
|
||||
|
||||
```bash
|
||||
git config --global pager.branch false
|
||||
git config --global pager.tag false
|
||||
```
|
||||
|
||||
30
converter.py
Executable file
@@ -0,0 +1,30 @@
|
||||
#!/usr/bin/env/python3
|
||||
|
||||
import subprocess
|
||||
import os
|
||||
import time
|
||||
|
||||
convert_dir = "/Users/ducoterra/Desktop/"
|
||||
debug = False
|
||||
|
||||
while True:
|
||||
# get a list of all .mov or .gif files
|
||||
movs = list(filter(lambda item: item.endswith(".mov"), os.listdir(convert_dir)))
|
||||
if debug:
|
||||
print(f"Found {len(movs)} .mov files.")
|
||||
gifs = list(filter(lambda item: item.endswith(".gif"), os.listdir(convert_dir)))
|
||||
if debug:
|
||||
print(f"Found {len(gifs)} .gif files.")
|
||||
|
||||
# find files that are not already gifs and aren't default
|
||||
not_done = list(filter(lambda mov: mov.replace(".mov",".gif") not in gifs and not mov.startswith("Screen Recording"), movs))
|
||||
if debug:
|
||||
print(f"Found {len(not_done)} to convert.")
|
||||
|
||||
for mov in not_done:
|
||||
print(f"converting {mov}. Ctrl + C to stop...")
|
||||
if debug:
|
||||
time.sleep(5)
|
||||
subprocess.run(['/usr/local/bin/ffmpeg', '-i', convert_dir + mov, '-filter:v', 'setpts=0.5*PTS', convert_dir + mov.replace(".mov",".gif")], capture_output=True)
|
||||
|
||||
time.sleep(1)
|
||||
124
docs/day0.md
@@ -8,9 +8,9 @@ Fortunately we can do some things to make your life easier. We can install an ID
|
||||
|
||||
(or skip to [I have a Mac](#i-have-a-mac))
|
||||
|
||||
### Install Git
|
||||
### Install Git (windows)
|
||||
|
||||
Git is a version control program, but you can think of it as your best friend in the cold, dark world of data loss. Git will make sure you don't lose progress. It lets you save your code at various stages and
|
||||
Git is a version control program, but you can think of it as your best friend in the cold, dark world of data loss. Git will make sure you don't lose progress. It lets you save your code at various stages and revert back to previous saves if you need to.
|
||||
|
||||
1. Head to <https://git-scm.com/>
|
||||
|
||||
@@ -20,7 +20,7 @@ Git is a version control program, but you can think of it as your best friend in
|
||||
|
||||
3. Run through the default install process
|
||||
|
||||
### Install Python
|
||||
### Install Python (windows)
|
||||
|
||||
1. Head to <https://www.python.org/>
|
||||
|
||||
@@ -32,83 +32,83 @@ Git is a version control program, but you can think of it as your best friend in
|
||||
|
||||

|
||||
|
||||
### Install VSCode
|
||||
### Install VSCode (windows)
|
||||
|
||||
Your most important tool as a programmer is a proper editor. It should offer you a wide selection of tools but get out of your way when you don't need it. VSCode is a great option in 2020. It has tons of extensions and support for almost every language you can throw at it.
|
||||
|
||||
1. Head to <https://code.visualstudio.com/>
|
||||
|
||||
1. Click on the download link
|
||||
2. Click on the download link
|
||||
|
||||

|
||||
|
||||
1. Run through the installer, select default options
|
||||
3. Run through the installer, select default options
|
||||
|
||||
1. Open VSCode
|
||||
4. Open VSCode
|
||||
|
||||

|
||||
|
||||
1. Uncheck "Show welcome page on startup"
|
||||
5. Uncheck "Show welcome page on startup"
|
||||
|
||||

|
||||
|
||||
1. Close out of the welcome page
|
||||
6. Close out of the welcome page
|
||||
|
||||

|
||||
|
||||
1. Open the terinal with <kbd>ctrl</kbd>+<kbd>~</kbd>
|
||||
7. Open the terinal with ++ctrl++ + ~
|
||||
|
||||
1. Click the dropdown that says `1: powershell` and click `Select Default Shell`
|
||||
8. Click the dropdown that says `1: powershell` and click `Select Default Shell`
|
||||
|
||||

|
||||
|
||||
1. Select Command Prompt
|
||||
9. Select Command Prompt
|
||||
|
||||

|
||||
|
||||
1. Kill the terminal by clicking the trash can icon
|
||||
10. Kill the terminal by clicking the trash can icon
|
||||
|
||||

|
||||
|
||||
1. Click the "extensions" button on the left to open the extensions page
|
||||
11. Click the "extensions" button on the left to open the extensions page
|
||||
|
||||

|
||||
|
||||
1. Search for "python"
|
||||
12. Search for "python"
|
||||
|
||||

|
||||
|
||||
1. Click on the first Python extension and click "install"
|
||||
13. Click on the first Python extension and click "install"
|
||||
|
||||

|
||||
|
||||
1. When the extension has finished installing, close out of the welcome window
|
||||
14. When the extension has finished installing, close out of the welcome window
|
||||
|
||||

|
||||
|
||||
1. Close out of the extension window
|
||||
15. Close out of the extension window
|
||||
|
||||

|
||||
|
||||
1. Reopen your document view by clicking the "documents" icon
|
||||
16. Reopen your document view by clicking the "documents" icon
|
||||
|
||||

|
||||
|
||||
### Create a "Projects" folder
|
||||
### Create a "Projects" folder (windows)
|
||||
|
||||
I keep all my projects in a folder called "Projects" in my home directory. On Windows this is at `C:\Users\<your username>\Projects`. Create this folder now. Bookmark it, put it in your favorites, don't lose it.
|
||||
|
||||
1. In your `Projects` folder create another folder called `my_website`
|
||||
|
||||
2. Switch to VSCode You can use <kbd>alt</kbd>+<kbd>tab</kbd> to quickly switch between windows. Press <kbd>ctrl</kbd>+<kbd>k</kbd>+<kbd>o</kbd> and select the projects/my_website folder
|
||||
2. Switch to VSCode You can use ++alt+tab++ to quickly switch between windows. Press ++ctrl++ + K + O and select the projects/my_website folder
|
||||
|
||||

|
||||
|
||||
### Create a virtual environment
|
||||
### Create a virtual environment (windows)
|
||||
|
||||
A python virtual environment is a folder that will hold your python installation for the project you're working on. You'll have a virtual environment for every project you create.
|
||||
|
||||
1. With your "my_website" folder open in VSCode open the terminal with <kbd>ctrl</kbd>+<kbd>~</kbd>
|
||||
1. With your "my_website" folder open in VSCode open the terminal with ++ctrl++ + ~
|
||||
|
||||

|
||||
|
||||
@@ -126,7 +126,7 @@ A python virtual environment is a folder that will hold your python installation
|
||||
|
||||

|
||||
|
||||
### Install Django
|
||||
### Install Django (windows)
|
||||
|
||||
Django is a pip package. Pip packages are other people's python code that you can download for free. In much the same way you downloaded VSCode and Python itself with your browser, we can download pip packages with "pip". Pip comes preinstalled with Python.
|
||||
|
||||
@@ -134,33 +134,33 @@ Django is a pip package. Pip packages are other people's python code that you ca
|
||||
|
||||

|
||||
|
||||
1. If you have a warning like above you can ignore it for now. Type `django-admin startproject config .`
|
||||
2. If you have a warning like above you can ignore it for now. Type `django-admin startproject config .`
|
||||
|
||||

|
||||
|
||||
1. Click on `manage.py`. You should see VSCode activate python extensions in the bottom left and select an interpretor. ('venv': venv) should be selected. You can ignore the message that says "linter pylint is not installed" - just close out of it.
|
||||
3. Click on `manage.py`. You should see VSCode activate python extensions in the bottom left and select an interpretor. ('venv': venv) should be selected. You can ignore the message that says "linter pylint is not installed" - just close out of it.
|
||||
|
||||

|
||||
|
||||
1. Close out of manage.py by clicking the 'x' at the top.
|
||||
4. Close out of manage.py by clicking the 'x' at the top.
|
||||
|
||||
1. Type `python manage.py runserver`
|
||||
5. Type `python manage.py runserver`
|
||||
|
||||

|
||||
|
||||
1. Open a browser and navigate to <http://localhost:8000>
|
||||
6. Open a browser and navigate to <http://localhost:8000>
|
||||
|
||||

|
||||
|
||||
1. You should see an install success page. If so, congratulations! You have successfully installed Django.
|
||||
7. You should see an install success page. If so, congratulations! You have successfully installed Django.
|
||||
|
||||
1. Stop running server by clicking in the terminal and typing <kbd>ctrl</kbd>+<kbd>C</kbd>. You have successfully completed Day 0!
|
||||
8. Stop running server by clicking in the terminal and typing ++ctrl++ + C. You have successfully completed Day 0!
|
||||
|
||||
## I have a Mac
|
||||
|
||||
### Install Git
|
||||
### Install Git (mac)
|
||||
|
||||
Git is a version control program, but you can think of it as your best friend in the cold, dark world of data loss. Git will make sure you don't lose progress. It lets you save your code at various stages and
|
||||
Git is a version control program, but you can think of it as your best friend in the cold, dark world of data loss. Git will make sure you don't lose progress. It lets you save your code at various stages and revert back to previous saves if you need to.
|
||||
|
||||
1. Head to <https://git-scm.com/>
|
||||
|
||||
@@ -170,7 +170,7 @@ Git is a version control program, but you can think of it as your best friend in
|
||||
|
||||
3. Run through the default install process
|
||||
|
||||
### Install Python
|
||||
### Install Python (mac)
|
||||
|
||||
1. Head to <https://www.python.org/>
|
||||
|
||||
@@ -182,87 +182,87 @@ Git is a version control program, but you can think of it as your best friend in
|
||||
|
||||

|
||||
|
||||
### Install VSCode
|
||||
### Install VSCode (mac)
|
||||
|
||||
Your most important tool as a programmer is a proper editor. It should offer you a wide selection of tools but get out of your way when you don't need it. VSCode is a great option in 2020. It has tons of extensions and support for almost every language you can throw at it.
|
||||
|
||||
1. Head to <https://code.visualstudio.com/>
|
||||
|
||||
1. Click on the download link
|
||||
2. Click on the download link
|
||||
|
||||

|
||||
|
||||
1. Run through the installer, select default options
|
||||
3. Run through the installer, select default options
|
||||
|
||||
1. Open VSCode
|
||||
4. Open VSCode
|
||||
|
||||

|
||||
|
||||
1. Uncheck "Show welcome page on startup"
|
||||
5. Uncheck "Show welcome page on startup"
|
||||
|
||||

|
||||
|
||||
1. Close out of the welcome page
|
||||
6. Close out of the welcome page
|
||||
|
||||

|
||||
|
||||
1. Click the "extensions" button on the left to open the extensions page
|
||||
7. Click the "extensions" button on the left to open the extensions page
|
||||
|
||||

|
||||
|
||||
1. Search for "python"
|
||||
8. Search for "python"
|
||||
|
||||

|
||||
|
||||
1. Click on the first Python extension and click "install"
|
||||
9. Click on the first Python extension and click "install"
|
||||
|
||||

|
||||
|
||||
1. When the extension has finished installing, close out of the welcome window
|
||||
10. When the extension has finished installing, close out of the welcome window
|
||||
|
||||

|
||||
|
||||
1. Close out of the extension window
|
||||
11. Close out of the extension window
|
||||
|
||||

|
||||
|
||||
1. Reopen your document view by clicking the "documents" icon
|
||||
12. Reopen your document view by clicking the "documents" icon
|
||||
|
||||

|
||||
|
||||
### Create a "Projects" folder
|
||||
### Create a "Projects" folder (mac)
|
||||
|
||||
I keep all my projects in a folder called "Projects" in my home directory. On MacOS this is at `/Users/<your username>/Projects`. Create this folder now. Bookmark it, put it in your favorites, don't lose it.
|
||||
|
||||
1. In your `Projects` folder create another folder called `my_website`
|
||||
|
||||
1. Switch to VSCode You can use <kbd>cmd</kbd>+<kbd>tab</kbd> to quickly switch between windows. Press <kbd>ctrl</kbd>+<kbd>o</kbd> and select the projects/my_website folder
|
||||
2. Switch to VSCode You can use ++cmd+tab++ to quickly switch between windows. Press ++ctrl++ + O and select the projects/my_website folder
|
||||
|
||||

|
||||
|
||||
### Create a virtual environment
|
||||
### Create a virtual environment (mac)
|
||||
|
||||
A python virtual environment is a folder that will hold your python installation for the project you're working on. You'll have a virtual environment for every project you create.
|
||||
|
||||
1. With your "my_website" folder open in VSCode open the terminal with <kbd>ctrl</kbd>+<kbd>~</kbd>
|
||||
1. With your "my_website" folder open in VSCode open the terminal with ++ctrl++ + ~
|
||||
|
||||

|
||||
|
||||
1. Type `python3 --version`
|
||||
2. Type `python3 --version`
|
||||
|
||||

|
||||
|
||||
1. If you see `Python 3.9.#` you have the correct version, if you see another version try typing `python3.9 --version`. If that doesn't work you'll need to reinstall python 3.9.
|
||||
3. If you see `Python 3.9.#` you have the correct version, if you see another version try typing `python3.9 --version`. If that doesn't work you'll need to reinstall python 3.9.
|
||||
|
||||
1. Type `python3 -m venv venv`. You'll see a folder appear on the left side of VSCode.
|
||||
4. Type `python3 -m venv venv`. You'll see a folder appear on the left side of VSCode.
|
||||
|
||||

|
||||
|
||||
1. Source your venv: type `source venv/bin/activate`. You'll see a (venv) appear next to your terminal cursor.
|
||||
5. Source your venv: type `source venv/bin/activate`. You'll see a (venv) appear next to your terminal cursor.
|
||||
|
||||

|
||||
|
||||
### Install Django
|
||||
### Install Django (mac)
|
||||
|
||||
Django is a pip package. Pip packages are other people's python code that you can download for free. In much the same way you downloaded VSCode and Python itself with your browser, we can download pip packages with "pip". Pip comes preinstalled with Python.
|
||||
|
||||
@@ -270,24 +270,24 @@ Django is a pip package. Pip packages are other people's python code that you ca
|
||||
|
||||

|
||||
|
||||
1. If you have a warning like above you can ignore it for now. Type `django-admin startproject config .`
|
||||
2. If you have a warning like above you can ignore it for now. Type `django-admin startproject config .`
|
||||
|
||||

|
||||
|
||||
1. Click on `manage.py`. You should see VSCode activate python extensions in the bottom left and select an interpretor. ('venv': venv) should be selected. You can ignore the message that says "linter pylint is not installed" - just close out of it.
|
||||
3. Click on `manage.py`. You should see VSCode activate python extensions in the bottom left and select an interpretor. ('venv': venv) should be selected. You can ignore the message that says "linter pylint is not installed" - just close out of it.
|
||||
|
||||

|
||||
|
||||
1. Close out of manage.py by clicking the 'x' at the top.
|
||||
4. Close out of manage.py by clicking the 'x' at the top.
|
||||
|
||||
1. Type `python manage.py runserver`
|
||||
5. Type `python manage.py runserver`
|
||||
|
||||

|
||||
|
||||
1. Open a browser and navigate to <http://localhost:8000>
|
||||
6. Open a browser and navigate to <http://localhost:8000>
|
||||
|
||||

|
||||
|
||||
1. You should see an install success page. If so, congratulations! You have successfully installed Django.
|
||||
7. You should see an install success page. If so, congratulations! You have successfully installed Django.
|
||||
|
||||
1. Stop running server by clicking in the terminal and typing <kbd>ctrl</kbd>+<kbd>C</kbd>. You have successfully completed Day 0!
|
||||
8. Stop running server by clicking in the terminal and typing ++ctrl++ + C. You have successfully completed Day 0!
|
||||
|
||||
87
docs/day1.md
@@ -38,9 +38,9 @@ Before we can dive into our web project we have to cover some Python basics. Let
|
||||
|
||||
15. Type `address` and press enter. You should see the address print to the terminal. Tuples can hold multiple types of data - 123 is a number and "lane ave" is a string.
|
||||
|
||||
16. Type `len(address)` and press enter. You should see `5` printed to the terminal. There are 5 "things" in the tuple:
|
||||
16. Type `len(address)` and press enter. You should see `5` printed to the terminal. There are 5 "things" in the tuple:
|
||||
|
||||
(1) `123 `
|
||||
(1) `123`
|
||||
|
||||
(2) `"lane ave"`
|
||||
|
||||
@@ -72,22 +72,21 @@ Before we can dive into our web project we have to cover some Python basics. Let
|
||||
|
||||

|
||||
|
||||
|
||||
1. In this file type `print('hello, world!')` and save with <kbd>ctrl</kbd>+<kbd>S</kbd>
|
||||
2. In this file type `print('hello, world!')` and save with ++ctrl++ + S
|
||||
|
||||

|
||||
|
||||
1. In the terminal type `python my_program.py` and press enter. You should see `hello, world!` printed to the terminal.
|
||||
3. In the terminal type `python my_program.py` and press enter. You should see `hello, world!` printed to the terminal.
|
||||
|
||||

|
||||
|
||||
1. Congratulations! You ran your first python file. Just like the python command prompt above, running `python <filename>` on a file with python code in it will execute that python code. Now we can run multiple lines of python at once!
|
||||
4. Congratulations! You ran your first python file. Just like the python command prompt above, running `python <filename>` on a file with python code in it will execute that python code. Now we can run multiple lines of python at once!
|
||||
|
||||
1. Below `print('hello, world!')` type `print('goodbye!)`
|
||||
5. Below `print('hello, world!')` type `print('goodbye!)`
|
||||
|
||||

|
||||
|
||||
1. Below `print('goodbye')` type
|
||||
6. Below `print('goodbye')` type
|
||||
|
||||
```python
|
||||
x = 1
|
||||
@@ -99,7 +98,7 @@ Before we can dive into our web project we have to cover some Python basics. Let
|
||||
|
||||

|
||||
|
||||
1. Save the file with <kbd>ctrl</kbd>+<kbd>S</kbd>. In your terminal type `python myprogram.py` and press enter. You should see
|
||||
7. Save the file with ++ctrl++ + S. In your terminal type `python myprogram.py` and press enter. You should see
|
||||
|
||||
```bash
|
||||
hello, world!
|
||||
@@ -110,29 +109,29 @@ Before we can dive into our web project we have to cover some Python basics. Let
|
||||
|
||||
printed to the terminal
|
||||
|
||||
1. This is out of order. We want to print "goodbye" last. Let's fix that with functions.
|
||||
8. This is out of order. We want to print "goodbye" last. Let's fix that with functions.
|
||||
|
||||
1. Above `print('hello, world!')` type `def print_hello():`
|
||||
9. Above `print('hello, world!')` type `def print_hello():`
|
||||
|
||||

|
||||
|
||||
1. Indent `print('hello, world!')` by pressing <kbd>tab</kbd>
|
||||
10. Indent `print('hello, world!')` by pressing ++tab++
|
||||
|
||||

|
||||
|
||||
1. Give 'goodbye' the same treatment. This time type `def print_goodbye():`
|
||||
11. Give 'goodbye' the same treatment. This time type `def print_goodbye():`
|
||||
|
||||

|
||||
|
||||
1. Finally add `def middle_stuff():` above the remaining cod
|
||||
12. Finally add `def middle_stuff():` above the remaining cod
|
||||
|
||||

|
||||
|
||||
1. Save the file with <kbd>ctrl</kbd>+<kbd>S</kbd>. Now type `python my_program.py` in the terminal and press enter. Nothing will return.
|
||||
13. Save the file with ++ctrl++ + S. Now type `python my_program.py` in the terminal and press enter. Nothing will return.
|
||||
|
||||

|
||||
|
||||
1. We've given our snippets of code "names" by adding a "def" above them. These are called functions. We can call them in any order we want. Let's call them in the correct order by using their names. Add the following to the bottom of my_program.py
|
||||
14. We've given our snippets of code "names" by adding a "def" above them. These are called functions. We can call them in any order we want. Let's call them in the correct order by using their names. Add the following to the bottom of my_program.py
|
||||
|
||||
```python
|
||||
print_hello()
|
||||
@@ -140,7 +139,7 @@ Before we can dive into our web project we have to cover some Python basics. Let
|
||||
print_goodbye()
|
||||
```
|
||||
|
||||
1. Type `python my_program.py` in the terminal and press enter. Now everything prints in order!
|
||||
15. Type `python my_program.py` in the terminal and press enter. Now everything prints in order!
|
||||
|
||||

|
||||
|
||||
@@ -150,88 +149,90 @@ Now that we can write some basic python we can begin our django project. Let's s
|
||||
|
||||
1. Close out of my_program.py
|
||||
|
||||
1. In the terminal type `django-admin startapp mysite`
|
||||
2. In the terminal type `django-admin startapp mysite`
|
||||
|
||||

|
||||
|
||||
1. Expand the `config` folder by clicking on it
|
||||
3. Expand the `config` folder by clicking on it
|
||||
|
||||

|
||||
|
||||
1. Click on `settings.py` to open it
|
||||
4. Click on `settings.py` to open it
|
||||
|
||||
1. Scroll down to line 33 and add `mysite` above `'django.contrib.admin'`
|
||||
5. Scroll down to line 33 and add `mysite` above `'django.contrib.admin'`
|
||||
|
||||

|
||||
|
||||
1. Save with <kbd>ctrl</kbd>+<kbd>S</kbd>
|
||||
6. Save with ++ctrl++ + S
|
||||
|
||||
1. Click on `urls.py` to open it
|
||||
7. Click on `urls.py` to open it
|
||||
|
||||

|
||||
|
||||
1. On line 17 add `, include` after `from django.urls import path`
|
||||
8. On line 17 add `, include` after `from django.urls import path`
|
||||
|
||||

|
||||
|
||||
1. Add `path('', include('mysite.urls')),` above `path('admin/', admin.site.urls),`
|
||||
9. Add `path('', include('mysite.urls')),` above `path('admin/', admin.site.urls),`
|
||||
|
||||

|
||||
|
||||
1. Expand the newly created `mysite` folder by clicking on it
|
||||
10. Expand the newly created `mysite` folder by clicking on it
|
||||
|
||||

|
||||
|
||||
1. Right click on `mysite` and click "New Folder". Name it `templates`
|
||||
11. Right click on `mysite` and click "New Folder". Name it `templates`
|
||||
|
||||

|
||||
|
||||
1. Right click on `templates` and click "New Folder". Name it `mysite`
|
||||
12. Right click on `templates` and click "New Folder". Name it `mysite`
|
||||
|
||||

|
||||
|
||||
1. Right click on the `mysite` folder inside `templates` and click "New File". Name it `index.html`
|
||||
13. Right click on the `mysite` folder inside `templates` and click "New File". Name it `index.html`
|
||||
|
||||

|
||||
|
||||
1. Open `index.html` by clicking on it
|
||||
14. Open `index.html` by clicking on it
|
||||
|
||||
1. Add the following to index.html
|
||||
15. Add the following to index.html
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
|
||||
<body>
|
||||
{{ data }}
|
||||
</body>
|
||||
|
||||
</html>
|
||||
```
|
||||
|
||||

|
||||
|
||||
1. Save with <kbd>ctrl</kbd>+<kbd>S</kbd>
|
||||
16. Save with ++ctrl++ + S
|
||||
|
||||
1. Open `views.py` by clicking on it
|
||||
17. Open `views.py` by clicking on it
|
||||
|
||||
1. In views.py under line 3 add the following:
|
||||
18. In views.py under line 3 add the following:
|
||||
|
||||
```python
|
||||
def index(request):
|
||||
return render(
|
||||
request,
|
||||
"mysite/index.html",
|
||||
request,
|
||||
"mysite/index.html",
|
||||
{"data": "hello"}
|
||||
)
|
||||
```
|
||||
|
||||

|
||||
|
||||
1. Save with <kbd>ctrl</kbd>+<kbd>S</kbd>
|
||||
19. Save with ++ctrl++ + S
|
||||
|
||||
1. Right click on `mysite` and click "New File". Name it `urls.py`
|
||||
20. Right click on `mysite` and click "New File". Name it `urls.py`
|
||||
|
||||

|
||||
|
||||
1. Add the following to urls.py:
|
||||
21. Add the following to urls.py:
|
||||
|
||||
```python
|
||||
from django.urls import path
|
||||
@@ -244,14 +245,14 @@ Now that we can write some basic python we can begin our django project. Let's s
|
||||
|
||||

|
||||
|
||||
1. Save with <kbd>ctrl</kbd>+<kbd>S</kbd>
|
||||
22. Save with ++ctrl++ + S
|
||||
|
||||
1. In the terminal type `python manage.py runserver`
|
||||
23. In the terminal type `python manage.py runserver`
|
||||
|
||||

|
||||
|
||||
1. In your browser navigate to <http://localhost:8000>
|
||||
24. In your browser navigate to <http://localhost:8000>
|
||||
|
||||

|
||||
|
||||
You've now passed python data to a browser! We'll explore what this really means in Day 2.
|
||||
You've now passed python data to a browser! We'll explore what this really means in Day 2.
|
||||
|
||||
241
docs/day2.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# Day 2
|
||||
|
||||
## Back to the basics: and, or, not, if
|
||||
|
||||
Before we do anything more interesting we're going to have to cover our logical basics. In Python these are `not`, `and`, `or`, and `if`.
|
||||
|
||||
1. Stop your server with ++ctrl++ + C
|
||||
2. Type `python` in the terminal to open your python interpretor
|
||||
|
||||

|
||||
|
||||
|
||||
### not
|
||||
|
||||
1. Type `x = True` and press enter.
|
||||
2. Type `x` and press enter to see that x is true.
|
||||
3. Type `not x` and press enter. `not` inverts the value of `x`. So if `x` is True, `not x` is False.
|
||||
4. Type `not not x` and press enter. `not not x` inverts `not x`. You can chain `not` as many times as you want.
|
||||
5. Let's imagine we're building a weather app and we want to know if it's raining. Type `is_raining = True` and press enter.
|
||||
6. Type `print(f"should I wear a raincoat? {is_raining}")` and press enter.
|
||||
7. Today it's not raining. We could create a variable called `is_not_raining` but we could also just `not`. Type `print(f"should I wear a raincoat? {not is_raining}")`
|
||||
8. Type `not 'hello'` and press enter. This might seem strange but Python interprets a string as `True`. `not 'hello'` will return `False`.
|
||||
9. Type `not ''` and press enter. An empty string in Python is False. `not ''` returns `True`.
|
||||
|
||||
### and
|
||||
|
||||
1. In your terminal type `x = True` and press enter.
|
||||
2. Type `x` and press enter to see that x is True.
|
||||
3. Type `y = True` and press enter.
|
||||
4. Type `y` and press enter to see that y is True.
|
||||
5. Type `y and x` and press enter. `y` is true *and* `x` is true, so `y` and `x` is true.
|
||||
6. We're building our weather app to be more useful. We want to tell people if it's rainy and windy. Type `rainy = True` and press enter.
|
||||
7. Type `windy = True` and press enter.
|
||||
8. Type `rainy and windy` and press enter. We get True because it's rainy and windy.
|
||||
9. Today it's not windy. Type `rainy and not windy` and press enter. We get False because it isn't rainy *and* windy.
|
||||
10. Tomorrow it won't be windy and it also won't be rainy. Type `not rainy and not windy` and press enter. We get False because neither weather conditions are met.
|
||||
|
||||
### or
|
||||
|
||||
1. In your terminal type `x = True` and press enter.
|
||||
2. Type `x` and press enter to see that x is True.
|
||||
3. Type `y = False` and press enter.
|
||||
4. Type `y` and press enter to see that y is False.
|
||||
5. Type `y or x` and press enter. `x` is True so asking if x or y is true will result in `True`.
|
||||
6. Our weather app has millions of downloads. Our data suggests people don't like when it's cold or raining. Let's tell them when it's cold or raining.
|
||||
7. Type `cold = True` and press enter.
|
||||
8. Type `raining = True` and press enter.
|
||||
9. Type `cold or raining` and press enter. We get `True`, it is cold and it is raining.
|
||||
10. Today it isn't cold but it is raining. Type `not cold or raining`. We get `True`, it is still raining outside.
|
||||
11. Tomorrow it won't be cold and it won't be raining. Type `not cold or not raining`. We get `False` because neither of our disliked weather conditions are met.
|
||||
|
||||
### if
|
||||
|
||||
1. In your terminal type `x = True` and press enter.
|
||||
2. Type `x` and press enter to see that x is True.
|
||||
3. Type `y = False` and press enter.
|
||||
4. Type `y` and press enter to see that y is False.
|
||||
5. Type `if x:` and press enter. You'll see a `...`. Python is waiting for another input.
|
||||
6. Type ++tab++ `print('x is true!')` and press enter. You should see another `...`.
|
||||
7. Press enter again. 'x is true!' will print to the terminal.
|
||||
|
||||

|
||||
|
||||
8. Type `if y:` and press enter. Now type ++tab++ `print('y is true!')` and press enter twice. You won't see anything print.
|
||||
|
||||

|
||||
|
||||
9. Type `if not y:` and press enter. Now type ++tab++ `print('y is false!')` and press enter twice. You'll see 'y is false!') printed.
|
||||
10. Now that our weather app is sentient let's give it some decision making capability.
|
||||
11. Type `raining = True` and press enter.
|
||||
12. Type `if raining:` and press enter.
|
||||
13. Type ++tab++ `print('You should wear a rain jacket')` and press enter twice. Your weather app can now tell you to wear a jacket if it's raining outside.
|
||||
|
||||

|
||||
|
||||
14. Type `exit()` to exit
|
||||
|
||||
## Building a Terrible Weather App
|
||||
|
||||
1. Create a new file called `weather_app.py` by clicking the "add file" icon in the top left of VSCode.
|
||||
|
||||

|
||||
|
||||
2. We're going to create an app where the user has to guess the weather. We're going to need the python random module to generate random weather conditions. Add the following to the top of the page:
|
||||
|
||||
```python
|
||||
import random
|
||||
```
|
||||
|
||||

|
||||
|
||||
This tells python we intend to use the `random` package
|
||||
|
||||
3. We'll generate 4 weather conditions. Add the following after `import random`
|
||||
|
||||
```python
|
||||
warm = random.choice([True, False])
|
||||
cold = not warm
|
||||
raining = random.choice([True, False])
|
||||
snowing = not raining
|
||||
```
|
||||
|
||||

|
||||
|
||||
random.choice([True, False]) selects either True or False randomly.
|
||||
|
||||
4. Let's print our weather conditions in a cryptic way. Add the following below our variables:
|
||||
|
||||
```python
|
||||
if warm or cold:
|
||||
print("It's warm or cold.")
|
||||
|
||||
if raining or warm:
|
||||
print("It's raining or warm.")
|
||||
|
||||
if raining or snowing:
|
||||
print("It's raining or snowing.")
|
||||
|
||||
if cold or snowing:
|
||||
print("It's cold or snowing.")
|
||||
```
|
||||
|
||||

|
||||
|
||||
This will print weather conditions in pairs to make it more challenging for our users to guess the weather.
|
||||
|
||||
5. Now let's get our user input. Since we have 4 possible weather conditions we'll need 4 "guessing modules". Let's build the first one:
|
||||
|
||||
```python
|
||||
warm_guess = input("Is it warm? (y/n) ")
|
||||
if warm_guess == 'y' and warm:
|
||||
print('Correct!')
|
||||
elif warm_guess == 'n' and not warm:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||
```
|
||||
|
||||

|
||||
|
||||
We ask the user if it's warm. If they say 'y' and it is warm we tell them they got it right! If they guess wrong we tell them they are wrong.
|
||||
|
||||
6. We'll just repeat the guess module 3 more times for cold, raining, and snowing.
|
||||
|
||||
```python
|
||||
cold_guess = input("Is it cold? (y/n) ")
|
||||
if cold_guess == 'y' and cold:
|
||||
print('Correct!')
|
||||
elif cold_guess == 'n' and not cold:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||
|
||||
raining_guess = input("Is it raining? (y/n) ")
|
||||
if raining_guess == 'y' and raining:
|
||||
print('Correct!')
|
||||
elif raining_guess == 'n' and not raining:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||
|
||||
snowing_guess = input("Is it snowing? (y/n) ")
|
||||
if snowing_guess == 'y' and snowing:
|
||||
print('Correct!')
|
||||
elif snowing_guess == 'n' and not snowing:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||
```
|
||||
|
||||

|
||||
|
||||
7. Save with ++ctrl++ + S and run your weather app by typing `python weather_app.py`. Try to guess the weather.
|
||||
|
||||

|
||||
|
||||
## Pulling it all together with some Django
|
||||
|
||||
1. Let's make a weather app! Open "views.py" by clicking on it.
|
||||
|
||||

|
||||
|
||||
2. At the top of views.py add the following:
|
||||
|
||||
```python
|
||||
import random
|
||||
```
|
||||
|
||||

|
||||
|
||||
3. Now under all of our existing code in views.py add the following:
|
||||
|
||||
```python
|
||||
def weather(request):
|
||||
warm = random.choice([True, False])
|
||||
cold = not warm
|
||||
raining = random.choice([True, False])
|
||||
snowing = not raining
|
||||
|
||||
if warm:
|
||||
temperature_report = "It's warm out! Don't wear a jacket."
|
||||
else:
|
||||
temperature_report = "It's cold out! Wear a jacket."
|
||||
|
||||
if raining:
|
||||
precipitation_report = "It's raining! Bring an umbrella."
|
||||
else:
|
||||
precipitation_report = "It's snowing! Bring your skis."
|
||||
|
||||
return render(
|
||||
request,
|
||||
"mysite/index.html",
|
||||
{"data": temperature_report + " " + precipitation_report}
|
||||
)
|
||||
```
|
||||
|
||||

|
||||
|
||||
This creates a new "view" in our django app.
|
||||
|
||||
4. Open mysite/urls.py by clicking on it.
|
||||
|
||||

|
||||
|
||||
5. Under `path('', views.index),` add:
|
||||
|
||||
```python
|
||||
path('weather/', views.weather),
|
||||
```
|
||||
|
||||

|
||||
|
||||
6. Run your server with `python manage.py runserver` (if it isn't already running)
|
||||
|
||||

|
||||
|
||||
7. Navigate to <http://localhost:8000/weather>
|
||||
|
||||

|
||||
|
||||
Congratulations! You've added a new page to your app!
|
||||
352
docs/day3.md
Normal file
@@ -0,0 +1,352 @@
|
||||
# Day 3
|
||||
|
||||
## "For"
|
||||
|
||||
Let's cover our first loop - the "for" loop. In Python the "for" loop is absurdly powerful. Let me show you why.
|
||||
|
||||
### Looping without code
|
||||
|
||||
"For" loops in Python make intuitive sense even without code. I can demonstrate with this basket of fruit:
|
||||
|
||||
```text
|
||||
| |
|
||||
| apple |
|
||||
| banana |
|
||||
\ pear /
|
||||
\_____/
|
||||
```
|
||||
|
||||
For each fruit I want you to take it out of the basket say its name. You start with the apple, since it's at the top, and say "apple". Then you'd take out the banana and say "banana". Finally you'd take our the pear and say "pear".
|
||||
|
||||
In Python our "basket" is a list. Lists look like this:
|
||||
|
||||
```python
|
||||
["apple", "banana", "pear"]
|
||||
```
|
||||
|
||||
They're very similar to tuples. A list is "ordered", the first item in the list will always be the apple - much like the top item in the basket will always be the apple.
|
||||
|
||||
If I asked you to repeat the basket exercise above but with our python list - remove each item and say its name - you'd start with the apple, then remove the banana, and finally remove the pear.
|
||||
|
||||
### Looping with code
|
||||
|
||||
You saying the names of fruit out loud is funny but not very practical. Instead I want you to print the names of the fruit from our basket in the Python interpretor.
|
||||
|
||||
1. Start you interpretor by typing `python` and pressing ++enter++
|
||||
2. In your interpretor type the following:
|
||||
|
||||
```python
|
||||
fruits = ["apple", "banana", "pear"]
|
||||
for fruit in fruits:
|
||||
print(fruit)
|
||||
```
|
||||
|
||||
You should see the fruit print out:
|
||||
|
||||
```python
|
||||
>>> fruits = ["apple", "banana", "pear"]
|
||||
>>> for fruit in fruits:
|
||||
... print(fruit)
|
||||
...
|
||||
apple
|
||||
banana
|
||||
pear
|
||||
>>>
|
||||
```
|
||||
|
||||
you've just used a for loop!
|
||||
|
||||
3. So we can do something with each item in a list. But what if we need the index of each item? Type the following:
|
||||
|
||||
```python
|
||||
fruits = ["apple", "banana", "pear"]
|
||||
for index, fruit in enumerate(fruits):
|
||||
print(f"fruit {fruit} is at index {index}")
|
||||
```
|
||||
|
||||
with `enumerate` we can capture the position of the item and the item itself in the list.
|
||||
|
||||
Why is this useful?
|
||||
|
||||
4. We can modify elements in a list if we have their position. Paste the following and press enter:
|
||||
|
||||
```python
|
||||
fruits = ["apple", "banana", "pear"]
|
||||
print(f"Our original list is: {fruits}")
|
||||
```
|
||||
|
||||
Now let's modify our list. Type the following and press enter:
|
||||
|
||||
```python
|
||||
for index, fruit in enumerate(fruits):
|
||||
print(f"fruit {fruit} is at index {index}")
|
||||
if fruits[index] == "apple":
|
||||
fruits[index] = "apricot"
|
||||
print(f"fruit is still {fruit} but {fruits[index]} is at position {index} now")
|
||||
```
|
||||
|
||||
Now paste this:
|
||||
|
||||
```python
|
||||
print(f"Our modified list is: {fruits}")
|
||||
```
|
||||
|
||||
5. We can also loop through the contents of a dictionary. Let's recreate our dictionary from before:
|
||||
|
||||
```python
|
||||
vocabulary = {"apple": "the usually round, red or yellow, edible fruit of a small tree, Malus sylvestris, of the rose family.", "banana": "a tropical plant of the genus Musa, certain species of which are cultivated for their nutritious fruit."}
|
||||
```
|
||||
|
||||
Now we'll loop through the keys in the dictionary:
|
||||
|
||||
```python
|
||||
for word in vocabulary:
|
||||
print(word)
|
||||
```
|
||||
|
||||
We can access any item in the dictionary with its key:
|
||||
|
||||
```python
|
||||
for word in vocabulary:
|
||||
print(vocabulary[word])
|
||||
```
|
||||
|
||||
And we can access both the key and value by using the `items()` function:
|
||||
|
||||
```python
|
||||
for word, definition in vocabulary.items():
|
||||
print(f"{word}: {definition}")
|
||||
```
|
||||
|
||||
6. One common data format you'll run into is a list of dictionaries. You can think of this like spreadsheet columns:
|
||||
|
||||
| first name | last name | age |
|
||||
|-|-|-|
|
||||
| Jim | Fowler | 24 |
|
||||
| Bob | Jones | 36 |
|
||||
| Alice | Appleseed | 52 |
|
||||
|
||||
Behind the scenes this table data might look like:
|
||||
|
||||
```json
|
||||
[
|
||||
{"first name" : "Jim", "last name": "Fowler", "age": 24},
|
||||
{"first name" : "Bob", "last name": "Jones", "age": 36},
|
||||
{"first name" : "Alice", "last name": "Appleseed", "age": 52}
|
||||
]
|
||||
```
|
||||
|
||||
Notice how the headers are copied each time - this is the only way to ensure headers are preserved when translated to this format. This is called "json" and is the current preferred way to send data over the web.
|
||||
|
||||
Let's create this data in Python
|
||||
|
||||
```python
|
||||
people = [
|
||||
{"first name" : "Jim", "last name": "Fowler", "age": 24},
|
||||
{"first name" : "Bob", "last name": "Jones", "age": 36},
|
||||
{"first name" : "Alice", "last name": "Appleseed", "age": 52}
|
||||
]
|
||||
```
|
||||
|
||||
We're building a program that checks each person and lets you know if they're over 30 years old. This is easy with for loops:
|
||||
|
||||
```python
|
||||
for person in people:
|
||||
if person["age"] > 30:
|
||||
print(f"{person['first name']} {person['last name']} is over 30.")
|
||||
```
|
||||
|
||||
7. Another common data format is a dictionary of lists. You can think of this like acceptible responses on a web form:
|
||||
|
||||
The form below has 3 valid states and 4 valid emotions:
|
||||
|
||||
<label>Choose a state:</label>
|
||||
<select>
|
||||
<option>Ohio</option>
|
||||
<option>Virginia</option>
|
||||
<option>Alask</option>
|
||||
</select>
|
||||
|
||||
<label>How you are feeling today:</label>
|
||||
<select>
|
||||
<option>Happy</option>
|
||||
<option>Sad</option>
|
||||
<option>Excited</option>
|
||||
<option>Nope</option>
|
||||
</select>
|
||||
|
||||
These could be represented by the following data:
|
||||
|
||||
```json
|
||||
{
|
||||
"states": ["Ohio", "Virginia", "Alaska"],
|
||||
"emotions": ["Happy", "Sad", "Excited", "Nope"]
|
||||
}
|
||||
```
|
||||
|
||||
Let's add this data to python:
|
||||
|
||||
```python
|
||||
choices = {
|
||||
"states": ["Ohio", "Virginia", "Alaska"],
|
||||
"emotions": ["Happy", "Sad", "Excited", "Nope"]
|
||||
}
|
||||
```
|
||||
|
||||
Now imagine you have to check if someone entered the right answer when filling out the form. Type the following:
|
||||
|
||||
```python
|
||||
state = input("Type the state you live in: ")
|
||||
```
|
||||
|
||||
```python
|
||||
emotion = input("How are you feeling: ")
|
||||
```
|
||||
|
||||
```python
|
||||
if state in choices["states"]:
|
||||
print("Good state")
|
||||
else:
|
||||
print("I don't know where that is.")
|
||||
```
|
||||
|
||||
```python
|
||||
if emotion in choices["emotions"]:
|
||||
print("Same")
|
||||
else:
|
||||
print("Not a valid emotion")
|
||||
```
|
||||
|
||||
8. Exit your terminal with `exit()`
|
||||
|
||||
## Creating an API
|
||||
|
||||
You've got enough at this point to make a substantial API. Usually we'd write a python script at this point but we're going to build a Django API first this time. We'll use the people data we have above.
|
||||
|
||||
1. Open mysite/views.py
|
||||
2. At the top of views.py add the following:
|
||||
|
||||
```python hl_lines="3 3"
|
||||
import random
|
||||
from django.shortcuts import render
|
||||
from django.http import JsonResponse
|
||||
```
|
||||
|
||||
3. At the very bottom (below your weather function) add another function like so:
|
||||
|
||||
```python
|
||||
def api(request):
|
||||
people = [
|
||||
{"first name" : "Jim", "last name": "Fowler", "age": 24},
|
||||
{"first name" : "Bob", "last name": "Jones", "age": 36},
|
||||
{"first name" : "Alice", "last name": "Appleseed", "age": 52}
|
||||
]
|
||||
|
||||
return JsonResponse({"data": people})
|
||||
```
|
||||
|
||||
We're returning a "JsonResponse" this time. Remember how json is the current preferred way to send data over the web? Django has a formatter built in for it.
|
||||
|
||||
4. let's add a url that points to our api endpoint. Open mysite/urls.py.
|
||||
5. Add the following:
|
||||
|
||||
```python hl_lines="4 4"
|
||||
urlpatterns = [
|
||||
path('', views.index),
|
||||
path('weather/', views.weather),
|
||||
path('people/', views.api),
|
||||
]
|
||||
```
|
||||
|
||||
6. Start your server with `python manage.py runserver`
|
||||
7. Navigate to <http://localhost:8000/people>
|
||||
8. You should see people data!
|
||||
9. Stop your server with ++ctrl+c++
|
||||
|
||||
## Reading an API with python
|
||||
|
||||
You have an API! Now let's read it with python. This is one of the most common applications for python in a work environment.
|
||||
|
||||
1. First we need a pip package called `requests`. `requests` can make web requests on our behalf. Install it by typing the following in your terminal:
|
||||
|
||||
```bash
|
||||
pip install requests
|
||||
```
|
||||
|
||||

|
||||
|
||||
2. Let's make sure that install worked. Open the python prompt by typing `python`
|
||||
3. In your interpretor type:
|
||||
|
||||
```python
|
||||
import requests
|
||||
requests.get("https://google.com")
|
||||
```
|
||||
|
||||
You should see a `<Response [200]>`. That means everything worked!
|
||||
|
||||
4. Type `exit()` to exit.
|
||||
|
||||
5. Create a new file called `api.py` in your my_website folder:
|
||||
|
||||

|
||||
|
||||
6. Add the following to `api.py`
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
response = requests.get("http://localhost:8000")
|
||||
print(response.text)
|
||||
```
|
||||
|
||||
7. Save with ++ctrl+s++
|
||||
8. Run your server by typing `python manage.py runserver`
|
||||
9. Open a new terminal window by click the plus icon:
|
||||
|
||||

|
||||
|
||||
10. Type `python api.py` and press ++enter++
|
||||
|
||||

|
||||
|
||||
We got our index page! Now let's get our API call:
|
||||
|
||||
11. Modify api.py by changing our web call to <http://localhost:8000/people>
|
||||
|
||||
```python hl_lines="3 3"
|
||||
import requests
|
||||
|
||||
response = requests.get("http://localhost:8000/people")
|
||||
print(response.text)
|
||||
```
|
||||
|
||||
12. Type `python api.py` and press ++enter++
|
||||
|
||||

|
||||
|
||||
13. Now we want to save our api response as python data. Let's add the following to `api.py`
|
||||
|
||||
```python hl_lines="2 5-8"
|
||||
import requests
|
||||
import json
|
||||
|
||||
response = requests.get("http://localhost:8000/people")
|
||||
people = response.json()["data"]
|
||||
for person in people:
|
||||
if person["age"] > 30:
|
||||
print(f"{person['first name']} {person['last name']} is over 30.")
|
||||
```
|
||||
|
||||
14. Type `python api.py` and press ++enter++
|
||||
|
||||

|
||||
|
||||
You've just done one of the most important things in Python programming: used the results of an api call to do something!
|
||||
|
||||
15. Click the terminal dropdown and switch back to the terminal running your web server:
|
||||
|
||||

|
||||
|
||||
16. Stop your server with ++ctrl+c++
|
||||
17. Type `python api.py` and press ++enter++. Notice how you get an error that says "failed to establish new connection"? If requests can't connect to the web server you'll see this error. Remember it!
|
||||
437
docs/day4.md
Normal file
@@ -0,0 +1,437 @@
|
||||
# Day 4
|
||||
|
||||
## "While"
|
||||
|
||||
The last section covered the for loop - a useful loop when you have a finite number of things you need to do something with. A grocery list, api data, and application arguments could be massive but will always have a definite size. Let's talk about times when you don't know how many times to loop.
|
||||
|
||||
### Example 1: A Game
|
||||
|
||||
Let's imagine you're coding a checkers app. You might approach it like this:
|
||||
|
||||
1. Game Start
|
||||
2. Player 1 moves
|
||||
3. Check if player 2 has no remaining pieces
|
||||
4. Player 2 moves
|
||||
5. Check if player 1 has no remaining pieces
|
||||
6. Player 1 moves
|
||||
7. Check if player 2 has no remaining pieces
|
||||
8. Player 2 moves
|
||||
9. Check if player 1 has no remaining pieces
|
||||
10. ""
|
||||
11. ""
|
||||
12. ""
|
||||
13. ...
|
||||
|
||||
You'll need to do a lot of the same stuff over and over - that's great for a loop. Since you'll have no idea how long the game will go on you can't use a for loop because there aren't a finite number of things to loop through (although you could simple use [the longest checkers game](http://www.wylliedraughts.com/LongGame.htm#:~:text=The%20longest%20game%20that%20Wyllie,of%203%2Dmove%20restriction%20checkers.) as your starting point I suppose).
|
||||
|
||||
What we need is a loop that run indefinitey until a condition is met - namely that one player wins the game.
|
||||
|
||||
### Example 2: User Input
|
||||
|
||||
Let's build a menu system for a text-based app.
|
||||
|
||||
1. Open your python interpretor by typing `python` and pressing ++enter++
|
||||
2. In your python interpretor paste the following:
|
||||
|
||||
```python
|
||||
program_choices = ["print", "count", "add", "exit"]
|
||||
while True:
|
||||
choice = input(f"Please choose one of the following options: [{', '.join(program_choices)}]: ")
|
||||
if choice == "print":
|
||||
print("hello")
|
||||
elif choice == "count":
|
||||
print(", ".join(["1","2","3","4","5"]))
|
||||
elif choice == "add":
|
||||
num1 = input("first number: ")
|
||||
num2 = input("second number: ")
|
||||
try:
|
||||
print(f"Answer: {int(num1) + int(num2)}")
|
||||
except ValueError:
|
||||
print("You did not provide 2 valid numbers")
|
||||
elif choice == "exit":
|
||||
break
|
||||
else:
|
||||
print("invalid choice!")
|
||||
```
|
||||
|
||||
3. Exit the menu by typing 'exit'
|
||||
4. Type exit() to exit the python interpretor
|
||||
|
||||
This lets a user select from a variety of options and returns them to the start of the menu upon a selection. If their selection is invalid we tell them it's invalid and return them to the start anyway.
|
||||
|
||||
Since we don't know how many things a user will want to do with our menu we should use a while loop to loop indefinitely.
|
||||
|
||||
Note the line that says `break`. This is how you break out of a loop in python. as soon as you call `break` it will stop the loop.
|
||||
|
||||
### Easy looping
|
||||
|
||||
Now that we've seen a few examples let's run through the core of a while loop:
|
||||
|
||||
1. Type `python` and press ++enter++ to open the python interpretor.
|
||||
2. We can use a while loop to do something indefinitely. Type the following and press ++enter++ twice:
|
||||
|
||||
```python
|
||||
while True:
|
||||
print("hello")
|
||||
```
|
||||
|
||||
3. Press ++ctrl+c++ to stop the loop
|
||||
4. We can use a while loop like a for loop (though this isn't recommended - it's too easy to get stuck in an infinite loop). Type the following and press ++enter++ twice:
|
||||
|
||||
```python
|
||||
count_to = 10
|
||||
start_at = 1
|
||||
while start_at <= count_to:
|
||||
print(start_at)
|
||||
start_at += 1
|
||||
```
|
||||
|
||||
5. We can use a while loop to check multiple conditions. Type the following and press ++enter++:
|
||||
|
||||
```python
|
||||
import random
|
||||
day = 1
|
||||
raining = True
|
||||
temperature = "cold"
|
||||
while temperature == "cold" or raining == True:
|
||||
print(f"Day {day}: Stay inside")
|
||||
day += 1
|
||||
temperature = random.choice(["cold", "warm"])
|
||||
raining = random.choice([True, False])
|
||||
|
||||
print(f"Day {day}: It's safe")
|
||||
```
|
||||
|
||||
6. We can put while loops inside while loops (notice how we break out of each loop - this requires 2 break statements). Type the following and press ++enter++:
|
||||
|
||||
```python
|
||||
while True:
|
||||
print("loop 1")
|
||||
while True:
|
||||
print("loop 2")
|
||||
break
|
||||
break
|
||||
```
|
||||
|
||||
## Let's build a menu
|
||||
|
||||
We're going to build a piece of software that lets us interact with our people API. We should be able to:
|
||||
|
||||
1. List the people from our API
|
||||
2. Update the list by calling the API
|
||||
3. Clear the list
|
||||
4. Exit
|
||||
|
||||
Let's get started:
|
||||
|
||||
1. Create a new file in your root directory called "menu.py"
|
||||
2. Add the following to the top:
|
||||
|
||||
```python
|
||||
import requests
|
||||
```
|
||||
|
||||
3. Create the list_people function by adding the following:
|
||||
|
||||
```python hl_lines="3-5"
|
||||
import requests
|
||||
|
||||
def list_people(people):
|
||||
print(people)
|
||||
return people
|
||||
```
|
||||
|
||||
4. Now create the update_people function by adding the following:
|
||||
|
||||
```python hl_lines="5-12"
|
||||
def list_people(people):
|
||||
print(people)
|
||||
return people
|
||||
|
||||
def update_people(people):
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/people")
|
||||
people = response.json()["data"]
|
||||
print("successfully updated people.")
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Server is not running. Failed to update.")
|
||||
return people
|
||||
```
|
||||
|
||||
5. Now create the clear_people function by adding the following:
|
||||
|
||||
```python hl_lines="10-12"
|
||||
def update_people(people):
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/people")
|
||||
people = response.json()["data"]
|
||||
print("successfully updated people.")
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Server is not running. Failed to update.")
|
||||
return people
|
||||
|
||||
def clear_people(people):
|
||||
people = None
|
||||
return people
|
||||
```
|
||||
|
||||
6. Finally add the main loop:
|
||||
|
||||
```python hl_lines="5-19"
|
||||
def clear_people(people):
|
||||
people = None
|
||||
return people
|
||||
|
||||
if __name__ == "__main__":
|
||||
people = None
|
||||
choices = ["list", "update", "clear", "exit"]
|
||||
while True:
|
||||
choice = input(f"Please choose an option [{', '.join(choices)}]: ")
|
||||
if choice == "list":
|
||||
people = list_people(people)
|
||||
elif choice == "update":
|
||||
people = update_people(people)
|
||||
elif choice == "clear":
|
||||
people = clear_people(people)
|
||||
elif choice == "exit":
|
||||
break
|
||||
else:
|
||||
print("Invalid choice. Please try again.")
|
||||
```
|
||||
|
||||
7. Check your work. Your whole program should be 35 lines long and look like this:
|
||||
|
||||
```python
|
||||
import requests
|
||||
import json
|
||||
|
||||
def list_people(people):
|
||||
print(people)
|
||||
return people
|
||||
|
||||
def update_people(people):
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/people")
|
||||
people = response.json()["data"]
|
||||
print("successfully updated people.")
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Server is not running. Failed to update.")
|
||||
return people
|
||||
|
||||
def clear_people(people):
|
||||
people = None
|
||||
return people
|
||||
|
||||
if __name__ == "__main__":
|
||||
people = None
|
||||
choices = ["list", "update", "clear", "exit"]
|
||||
while True:
|
||||
choice = input(f"Please choose an option [{', '.join(choices)}]: ")
|
||||
if choice == "list":
|
||||
people = list_people(people)
|
||||
elif choice == "update":
|
||||
people = update_people(people)
|
||||
elif choice == "clear":
|
||||
people = clear_people(people)
|
||||
elif choice == "exit":
|
||||
break
|
||||
else:
|
||||
print("Invalid choice. Please try again.")
|
||||
```
|
||||
|
||||
8. Run the program by typing `python menu.py` and pressing ++enter++.
|
||||
9. Type "list" and press ++enter++. You should see "None" printed to the screen. We haven't updated our people yet!
|
||||
10. Type "update" and press ++enter++. You should see "Server is not running. Failed to update.". We didn't run our server!
|
||||
11. Open a new terminal by clicking the plus icon.
|
||||
12. Type `python manage.py runserver` and press ++enter++.
|
||||
13. Flip back over to your other terminal by using the dropdown menu.
|
||||
14. Type "update" and press ++enter++. You should see "successfully updated people."
|
||||
15. Type "list" again and press ++enter++. You should see your people print out.
|
||||
16. Type "clear" and press ++enter++.
|
||||
17. Type "list" again and press ++enter++. Your people should be cleared.
|
||||
18. Type "exit" to exit.
|
||||
19. Flip back over to your django terminal with the dropdown menu
|
||||
20. Press ++ctrl+c++ to stop the server
|
||||
|
||||
## Threading
|
||||
|
||||
One of the more difficult concepts in programming is threading and multiprocessing. It's rarely taught at an intro level but it's fairly easy to use.
|
||||
|
||||
A program runs in a "thread". When you run `python menu.py` it creates one thread that executes all code in order. Code at the end of your file can't run before code at the beginning of your file.
|
||||
|
||||
...unless it could. What if you have a super slow internet connection and you need to make an api call? You don't want it to slow down your whole menu.
|
||||
|
||||
Here's the idea: we tell our computer to make the slow call to our API in the background and continue letting the user mess with the menu.
|
||||
|
||||
Let's make that a reality by simulating a slow internet connection.
|
||||
|
||||
1. Open views.py
|
||||
2. For this part we're going to need the time library. "time" lets us pause code execution for a bit, simulating a slow internet. At the top of views.py add the following:
|
||||
|
||||
```python hl_lines="2 2"
|
||||
import random
|
||||
import time
|
||||
from django.shortcuts import render
|
||||
from django.http import JsonResponse
|
||||
```
|
||||
|
||||
3. Jump to the very bottom and add the highlighted code:
|
||||
|
||||
```python hl_lines="10-23"
|
||||
def api(request):
|
||||
people = [
|
||||
{"first name" : "Jim", "last name": "Fowler", "age": 24},
|
||||
{"first name" : "Bob", "last name": "Jones", "age": 36},
|
||||
{"first name" : "Alice", "last name": "Appleseed", "age": 52}
|
||||
]
|
||||
|
||||
return JsonResponse({"data": people})
|
||||
|
||||
def slow_api(request):
|
||||
people = []
|
||||
first_names = ["Liam", "Noah", "Oliver", "William", "Olivia", "Emma", "Ava", "Sophia", "Isabella"]
|
||||
last_names = ["Smith", "Johnson", "Anderson", "Brown", "Garcia", "Miller", "Martinez", "Chavez"]
|
||||
num_people = random.randint(1,100)
|
||||
|
||||
for person in range(num_people):
|
||||
time.sleep(.1)
|
||||
first_name = random.choice(first_names)
|
||||
last_name = random.choice(last_names)
|
||||
age = random.randint(1,100)
|
||||
people.append({"first_name": first_name, "last_name": last_name, "age": age})
|
||||
|
||||
return JsonResponse({"data": people})
|
||||
```
|
||||
|
||||
4. Save with ++ctrl+s++
|
||||
5. We need to add a URL, open urls.py
|
||||
6. Add the highlighted code:
|
||||
|
||||
```python hl_lines="8 8"
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index),
|
||||
path('weather/', views.weather),
|
||||
path('people/', views.api),
|
||||
path('slow/', views.slow_api),
|
||||
]
|
||||
```
|
||||
|
||||
7. Save with ++ctrl+s++
|
||||
8. Open a new terminal by clicking the plus icon.
|
||||
9. Type `python manage.py runserver` and press ++enter++.
|
||||
10. Flip back over to your other terminal by using the dropdown menu.
|
||||
11. Navigate to <http://localhost:8000/slow/> to see your api results. Notice how long the page takes to load.
|
||||
12. Let's try our menu.py with the new API. Open menu.py and update line 10:
|
||||
|
||||
```python hl_lines="3 3"
|
||||
def update_people(people):
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/slow")
|
||||
people = response.json()["data"]
|
||||
print("successfully updated people.")
|
||||
```
|
||||
|
||||
13. Save with ++ctrl+s++
|
||||
14. Open a new terminal by clicking the plus icon
|
||||
15. Type `python menu.py` and press ++enter++
|
||||
16. Type "list" and press ++enter++. You should see `None`
|
||||
17. Type "update" and press ++enter++. Notice the delay. While we're waiting for our api to respond our menu won't respond to any thing we type.
|
||||
18. Type "exit" to exit.
|
||||
19. Let's add the magic that will unblock our menu during an API call. At the top of menu.py add the following:
|
||||
|
||||
```python hl_lines="3 3"
|
||||
import requests
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
```
|
||||
|
||||
20. We need to modify our main program to call the update_people function in a different thread. To do this we need to keep track of a "future" object.
|
||||
|
||||
A future is something that hasn't finished executing yet. We don't know when it will finish but we assume that it will.
|
||||
|
||||
```python hl_lines="3 8 10"
|
||||
if __name__ == "__main__":
|
||||
people = None
|
||||
future = None
|
||||
choices = ["list", "update", "clear", "exit"]
|
||||
while True:
|
||||
choice = input(f"Please choose an option [{', '.join(choices)}]: ")
|
||||
if choice == "list":
|
||||
future, people = list_people(future, people)
|
||||
elif choice == "update":
|
||||
future = ThreadPoolExecutor().submit(update_people, people)
|
||||
elif choice == "clear":
|
||||
people = clear_people(people)
|
||||
elif choice == "exit":
|
||||
break
|
||||
else:
|
||||
print("Invalid choice. Please try again.")
|
||||
```
|
||||
|
||||
21. We need to modify the `list_people` function to handle a future. This ensures that new people will print after an update. Change the following:
|
||||
|
||||
```python hl_lines="1-4"
|
||||
def list_people(future, people):
|
||||
if future is not None and future.done():
|
||||
people = future.result()
|
||||
future = None
|
||||
print(people)
|
||||
return (future, people)
|
||||
```
|
||||
|
||||
22. Save with ++ctrl+s++
|
||||
23. Your menu.py should look like this:
|
||||
|
||||
```python
|
||||
import requests
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
def list_people(future, people):
|
||||
if future is not None and future.done():
|
||||
people = future.result()
|
||||
future = None
|
||||
print(people)
|
||||
return (future, people)
|
||||
|
||||
def update_people(people):
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/slow")
|
||||
people = response.json()["data"]
|
||||
print("successfully updated people.")
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Server is not running. Failed to update.")
|
||||
return people
|
||||
|
||||
def clear_people(people):
|
||||
people = None
|
||||
return people
|
||||
|
||||
if __name__ == "__main__":
|
||||
people = None
|
||||
future = None
|
||||
choices = ["list", "update", "clear", "exit"]
|
||||
while True:
|
||||
choice = input(f"Please choose an option [{', '.join(choices)}]: ")
|
||||
if choice == "list":
|
||||
future, people = list_people(future, people)
|
||||
elif choice == "update":
|
||||
future = ThreadPoolExecutor().submit(update_people, people)
|
||||
elif choice == "clear":
|
||||
people = clear_people(people)
|
||||
elif choice == "exit":
|
||||
break
|
||||
else:
|
||||
print("Invalid choice. Please try again.")
|
||||
```
|
||||
|
||||
24. Now run `python menu.py`
|
||||
25. Type `list` and press ++enter++. Notice how there's nothing in the list.
|
||||
26. Type `update` and press ++enter++. Notice the menu returns instantly.
|
||||
27. In a moment you'll see "successfully updated people" print. Type `list` and press ++enter++.
|
||||
28. Type `clear` and press ++enter++
|
||||
29. Now type `update` and press ++enter++ and quickly type `list` and press ++enter++ before it updates. Notice you can interact with the menu before the result returns!
|
||||
30. You've successfully written a multithreaded program. Type `exit` to exit.
|
||||
31. Flip back to your django server terminal with the dropdown
|
||||
32. Press ++ctrl+c++ to stop the server.
|
||||
362
docs/day5.md
Normal file
@@ -0,0 +1,362 @@
|
||||
# Day 5
|
||||
|
||||
## "import"
|
||||
|
||||
In our last section we're going to talk about organization. Not a glamorous topic, but an important one nonetheless!
|
||||
|
||||
### What an import actually is
|
||||
|
||||
You've already done this quite a bit - but here's a recap
|
||||
|
||||
1. Type `python` in the terminal and press ++enter++ to start the interpretor
|
||||
2. Type `requests.get("https://google.com")` and press ++enter++
|
||||
3. You should see `NameError: name 'requests' is not defined` printed to the terminal
|
||||
4. Type `import requests` and press ++enter++
|
||||
5. Now type `requests.get("https://google.com")` again and press ++enter++
|
||||
6. You should see `<Response [200]>` printed to the terminal. You've just imported a module.
|
||||
7. Type `exit()` and press ++enter++ to exit
|
||||
|
||||
"importing" alerts python that you want to use some code that isn't in the file you're currently working in. But where is "requests"? Remember that "venv" folder we made? Look inside it:
|
||||
|
||||

|
||||
|
||||
Requests is just a bit of python code that lives in our venv. In fact, we can rename it and import it as something completely different (though this isn't recommended). Give this a try:
|
||||
|
||||
1. Rename the requests folder in your venv to "somethingelse"
|
||||
2. Type `python` in the terminal and press ++enter++ to open the interpretor
|
||||
3. Type `import somethingelse` and press ++enter++
|
||||
4. Type `somethingelse.get("https://google.com")` and press ++enter++. You should see `<Response [200]>` printed to the terminal. Your rename worked! You just changed the name python references when we import the code.
|
||||
5. Type `exit()` and press ++enter++ to exit.
|
||||
6. Rename "somethingelse" back to " for now.
|
||||
|
||||
|
||||
### Using "as" to rename imports
|
||||
|
||||
Sometimes we don't want to use the name of the package in our code. It might conflict with something we already named, it might be really long to type, or it might just be poorly named. Fortunately, we don't have to rename the folder to change the name.
|
||||
|
||||
1. Type `python` in the terminal and press ++enter++ to open the interpretor
|
||||
2. Type `import requests as somethingelse` and press enter
|
||||
3. Type `somethingelse.get("https://google.com")` and press ++enter++. You should see `<Response [200]>` printed to the terminal. You can use `as` to rename modules.
|
||||
4. Type `import requests` and press ++enter++
|
||||
5. Type `requests.get("https://google.com")` and press ++enter++. You should see `<Response [200]>` printed to the terminal. You can import requests like normal alongside your custom name.
|
||||
6. Type `exit()` and press ++enter++ to exit
|
||||
|
||||
### dots
|
||||
|
||||
When you type `requests.get()` have you considered what the `.` means? Anytime you see a `.` it means you can split that thing apart. Example:
|
||||
|
||||
```text
|
||||
requests . get
|
||||
└──────┘ ^ └─┘
|
||||
```
|
||||
|
||||
are two separate things.
|
||||
|
||||
`requests` is a "package". A package can container other packages, classes, functions, variables, etc.
|
||||
|
||||
`get` is a "function". That means it was created like this:
|
||||
|
||||
```python
|
||||
def get(url, ...):
|
||||
*code here*
|
||||
```
|
||||
|
||||
Check around line 64 in `venv/lib/python3/site-packages/requests/api.py` to see the actual function.
|
||||
|
||||
Let's actually make use of that dot.
|
||||
|
||||
1. Type `python` in the terminal and press ++enter++
|
||||
2. Type `from requests import get` and press ++enter++
|
||||
3. Type `requests.get("https://google.com")` and press ++enter++
|
||||
4. You should see `NameError: name 'requests' is not defined` printed to the terminal
|
||||
5. Type `get("https://google.com")` and press ++enter++. You should see `<Response [200]>` printed to the terminal. You just split the `get` function from the `requests` package. You don't need to type `requests.` to use the `get` function.
|
||||
6. Type `post("https://google.com")` and press ++enter++. You should see `NameError: name 'post' is not defined` printed to the terminal. `post` is a valid function, let's import it.
|
||||
7. Type `from requests import *` and press ++enter++. We just used a "wildcard" import. It import everything into our interpretor from the package..
|
||||
8. Type `post("https://google.com")` and press ++enter++. You should see `<Response [405]>` printed to the terminal. You didn't need to `from requests import post` to use the `post` function. You imported it when you used the `*` symbol.
|
||||
9. Type `exit()` and press ++enter++ to exit.
|
||||
|
||||
## Breaking apart our terrible weather app
|
||||
|
||||
What better way to demonstrate the power of imports than with our terrible weather app?
|
||||
|
||||
1. Type `python weather_app.py` in your terminal and press ++enter++. You should run through your terrible weather app just like on day 2
|
||||
2. Open "weather_app.py" in VSCode
|
||||
3. Notice the `import random` at the top, you should know what's happening here.
|
||||
4. Create a new file called `weather_config.py` in the root directory
|
||||
|
||||

|
||||
|
||||
5. Copy the 4 variables from the top of "weather_app.py" into "weather_config.py"
|
||||
|
||||

|
||||
|
||||
6. Save with ++ctrl+s++
|
||||
|
||||
7. Delete those variables from "weather_app.py".
|
||||
|
||||

|
||||
|
||||
8. Save with ++ctrl+s++
|
||||
|
||||
9. Delete `import random` from the top of "weather_app.py"
|
||||
10. Save with ++ctrl+s++
|
||||
11. Add `import random` to the top of "weather_config.py"
|
||||
|
||||
```python hl_lines="1 2"
|
||||
import random
|
||||
|
||||
warm = random.choice([True, False])
|
||||
cold = not warm
|
||||
raining = random.choice([True, False])
|
||||
snowing = not raining
|
||||
```
|
||||
|
||||
12. Save with ++ctrl+s++
|
||||
13. In your terminal type `python weather_app.py` and press ++enter++. You should see `NameError: name 'warm' is not defined` print to the terminal. But `warm` is in our weather_config.py! We need to import it!
|
||||
14. At the top of "weather_app.py" add `from weather_config import warm`
|
||||
|
||||
```python hl_lines="1 2"
|
||||
from weather_config import warm
|
||||
|
||||
if warm or cold:
|
||||
print("It's warm or cold.")
|
||||
|
||||
if raining or warm:
|
||||
```
|
||||
|
||||
15. Save with ++ctrl+s++
|
||||
16. Type `python weather_app.py` again and press ++enter++. This time you should see `NameError: name 'cold' is not defined` printed to your terminal. Ah, we imported warm but none of the other variables. We need to import those as well. We could type everything out one by one, but instead:
|
||||
17. At the top of "weather_app.py" change `from weather_config import warm` to `from weather_config import *`
|
||||
18. Save with ++ctrl+s++
|
||||
19. Now type `python weather_app.py` again and press ++enter++. Your weather app works as normal!
|
||||
|
||||
### Breaking it even further apart
|
||||
|
||||
We're going to turn each "chunk" of code in our weather app into a function that we can move to another file.
|
||||
|
||||
1. Starting at line 3, add the following (**indent the if statements!**):
|
||||
|
||||
```python hl_lines="1 1"
|
||||
def print_clues():
|
||||
--->if warm or cold:
|
||||
--->--->print("It's warm or cold.")
|
||||
|
||||
--->if raining or warm:
|
||||
--->--->print("It's raining or warm.")
|
||||
|
||||
--->if raining or snowing:
|
||||
--->--->print("It's raining or snowing.")
|
||||
|
||||
--->if cold or snowing:
|
||||
--->--->print("It's cold or snowing.")
|
||||
```
|
||||
|
||||

|
||||
|
||||
2. Now do the same to our "guess chunks" like so:
|
||||
|
||||
```python hl_lines="1 1"
|
||||
def check_guesses():
|
||||
--->warm_guess = input("Is it warm? (y/n) ")
|
||||
--->if warm_guess == 'y' and warm:
|
||||
--->--->print('Correct!')
|
||||
--->elif warm_guess == 'n' and not warm:
|
||||
--->--->print('Correct!')
|
||||
--->else:
|
||||
--->--->print('Wrong!')
|
||||
|
||||
--->cold_guess = input("Is it cold? (y/n) ")
|
||||
--->if cold_guess == 'y' and cold:
|
||||
--->--->print('Correct!')
|
||||
--->elif cold_guess == 'n' and not cold:
|
||||
--->--->print('Correct!')
|
||||
--->else:
|
||||
--->--->print('Wrong!')
|
||||
|
||||
--->raining_guess = input("Is it raining? (y/n) ")
|
||||
--->if raining_guess == 'y' and raining:
|
||||
--->--->print('Correct!')
|
||||
--->elif raining_guess == 'n' and not raining:
|
||||
--->--->print('Correct!')
|
||||
--->else:
|
||||
--->--->print('Wrong!')
|
||||
|
||||
--->snowing_guess = input("Is it snowing? (y/n) ")
|
||||
--->if snowing_guess == 'y' and snowing:
|
||||
--->--->print('Correct!')
|
||||
--->elif snowing_guess == 'n' and not snowing:
|
||||
--->--->print('Correct!')
|
||||
--->else:
|
||||
--->--->print('Wrong!')
|
||||
```
|
||||
|
||||

|
||||
|
||||
3. Save with ++ctrl+s++
|
||||
4. Type `python weather_app.py` in the terminal and press ++enter++. Nothing happens!
|
||||
5. Create a new file called "weather_run.py" in your root directory.
|
||||
|
||||

|
||||
|
||||
6. Add the following to "weather_run.py"
|
||||
|
||||
```python
|
||||
from weather_app import print_clues, check_guesses
|
||||
|
||||
print_clues()
|
||||
check_guesses()
|
||||
```
|
||||
|
||||
7. Save with ++ctrl+s++
|
||||
8. In your terminal type `python weather_run.py` and press ++enter++. Your weather app works again! You've broken it out into a bunch of modules.
|
||||
9. Type `python` in your terminal and press ++enter++ to open the python interpretor
|
||||
10. Type `import weather_run` and press ++enter++. Your weather app should run in the terminal
|
||||
11. Press ++ctrl+c++ to stop your app from running
|
||||
12. Type `exit()` to exit
|
||||
13. We don't want your app to run when we import it. Let's add a check to "weather_run.py" to make sure that doesn't happen. Modify "weather_run.py" like so:
|
||||
|
||||
```python hl_lines="3 3"
|
||||
from weather_app import print_clues, check_guesses
|
||||
|
||||
if __name__ == "__main__":
|
||||
--->print_clues()
|
||||
--->check_guesses()
|
||||
```
|
||||
|
||||

|
||||
|
||||
14. Type `python` in your terminal and press ++enter++ to open the python interpretor
|
||||
15. Type `import weather_run` and press ++enter++. This time nothing should happen! That's good, we want to import our app without it running immediately. Just like importing `requests` doesn't immediately run the `get` function, we don't want anything to run on import of our programs.
|
||||
16. Type `exit()` to exit
|
||||
|
||||
## Importing our menu
|
||||
|
||||
We can use imports to make our lives a lot easier. Let's use our menu as an example.
|
||||
|
||||
1. Open "menu.py" in VSCode
|
||||
2. Type `python` in your terminal and press ++enter++ to open the python interpretor
|
||||
3. Type `import menu` and press enter. You've just imported all our functions from "menu.py". Notice how the menu doesn't run though, that's because we added a `if __name__ == "__main__"` block! We were thinking ahead.
|
||||
4. Open a new terminal windows by clicking the plus icon
|
||||
5. Type `python manage.py runserver` and press ++enter++ to start your server
|
||||
6. Use the dropdown to switch back to your other terminal window
|
||||
7. Type `menu.update_people(None)` and press ++enter++. You should see people print to the terminal. But wait, that's not what update() was supposed to do - and why did we have to specify `(None)`?
|
||||
|
||||
If we want our menu functions to be useful outside our menu app we have some work to do:
|
||||
|
||||
1. First, I shouldn't have to pass a default value like `(None)` to our functions. Edit `list_people` like so:
|
||||
|
||||
```python hl_lines="1 1"
|
||||
def list_people(future=None, people=None):
|
||||
if future is not None and future.done():
|
||||
people = future.result()
|
||||
future = None
|
||||
print(people)
|
||||
return (future, people)
|
||||
```
|
||||
|
||||
This specifies that unless a "future" or "people" is provided they are "None" by default.
|
||||
|
||||
2. Let's do that to our remaining functions:
|
||||
|
||||
```python hl_lines="1 10"
|
||||
def update_people(people=None):
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/slow")
|
||||
people = response.json()["data"]
|
||||
print("successfully updated people.")
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Server is not running. Failed to update.")
|
||||
return people
|
||||
|
||||
def clear_people(people=None):
|
||||
people = None
|
||||
return people
|
||||
```
|
||||
|
||||
3. Now let's fix our update function. `update_people` is supposed to run in the background, but it just returned the list of people. Let's create a "decorator".
|
||||
|
||||
4. At the top of `menu.py` add the following:
|
||||
|
||||
```python hl_lines="5-8"
|
||||
import requests
|
||||
import json
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
def run_in_background(function):
|
||||
def wrapper(*args, **kwargs):
|
||||
return ThreadPoolExecutor().submit(function, *args, **kwargs)
|
||||
return wrapper
|
||||
|
||||
def list_people(future, people):
|
||||
if future is not None and future.done():
|
||||
people = future.result()
|
||||
future = None
|
||||
```
|
||||
|
||||
5. Now add the following above `update_people()`:
|
||||
|
||||
```python hl_lines="1 1"
|
||||
@run_in_background
|
||||
def update_people(people):
|
||||
try:
|
||||
response = requests.get("http://localhost:8000/slow")
|
||||
people = response.json()["data"]
|
||||
print("successfully updated people.")
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("Server is not running. Failed to update.")
|
||||
return people
|
||||
```
|
||||
|
||||
6. Remove the `ThreadPoolExecutor()` part at line 40:
|
||||
|
||||
```python hl_lines="10 10"
|
||||
if __name__ == "__main__":
|
||||
people = None
|
||||
future = None
|
||||
choices = ["list", "update", "clear", "exit"]
|
||||
while True:
|
||||
choice = input(f"Please choose an option [{', '.join(choices)}]: ")
|
||||
if choice == "list":
|
||||
future, people = list_people(future, people)
|
||||
elif choice == "update":
|
||||
future = update_people(people)
|
||||
elif choice == "clear":
|
||||
people = clear_people(people)
|
||||
elif choice == "exit":
|
||||
break
|
||||
else:
|
||||
print("Invalid choice. Please try again.")
|
||||
```
|
||||
|
||||
7. Let's make sure we didn't break our menu. Type `python menu.py` and press ++enter++
|
||||
8. Type update, list, clear, and exit to test your program.
|
||||
9. Type `python` and press ++enter++ to open the interpretor
|
||||
10. Type `import menu` and press ++enter++
|
||||
11. Type `people = menu.list_people()` and press ++enter++. You should see `None` print.
|
||||
12. Now type `update = menu.update_people()` and press ++enter++. Nothing should print.
|
||||
13. Wait a moment for "successfully updated people." to print to the terminal
|
||||
14. Type `people = menu.list_people(update)`. Your people should list! You successfully turned your menu into an importable package!
|
||||
15. Type `exit()` to exit.
|
||||
|
||||
### Using our imported menu
|
||||
|
||||
For our last trick we'll use our menu functions in a new program.
|
||||
|
||||
1. Create a new file named "print_people.py"
|
||||
|
||||

|
||||
|
||||
2. Add the following:
|
||||
|
||||
```python
|
||||
from menu import update_people, list_people
|
||||
from concurrent.futures import wait
|
||||
|
||||
update = update_people()
|
||||
wait([update])
|
||||
list_people(update)
|
||||
```
|
||||
|
||||
3. Type `python print_people.py` and press ++enter++ to run your program. You should see your people print after a while.
|
||||
|
||||
Congratulations! You've just imported a program you wrote to communciate with an API and used it to do something automatically.
|
||||
BIN
docs/img/day2/add_weather.gif
Normal file
|
After Width: | Height: | Size: 367 KiB |
BIN
docs/img/day2/add_weather_path.gif
Normal file
|
After Width: | Height: | Size: 465 KiB |
BIN
docs/img/day2/conditions.png
Normal file
|
After Width: | Height: | Size: 162 KiB |
BIN
docs/img/day2/create_file.gif
Normal file
|
After Width: | Height: | Size: 123 KiB |
BIN
docs/img/day2/django_random.gif
Normal file
|
After Width: | Height: | Size: 359 KiB |
BIN
docs/img/day2/if_interpreter.gif
Normal file
|
After Width: | Height: | Size: 342 KiB |
BIN
docs/img/day2/if_prints.png
Normal file
|
After Width: | Height: | Size: 183 KiB |
BIN
docs/img/day2/import_random.png
Normal file
|
After Width: | Height: | Size: 155 KiB |
BIN
docs/img/day2/modules.png
Normal file
|
After Width: | Height: | Size: 254 KiB |
BIN
docs/img/day2/navigate_to_weather.gif
Normal file
|
After Width: | Height: | Size: 130 KiB |
BIN
docs/img/day2/open_urls.gif
Normal file
|
After Width: | Height: | Size: 204 KiB |
BIN
docs/img/day2/open_views.gif
Normal file
|
After Width: | Height: | Size: 260 KiB |
BIN
docs/img/day2/python_manage_run.gif
Normal file
|
After Width: | Height: | Size: 231 KiB |
BIN
docs/img/day2/rain_jacket.gif
Normal file
|
After Width: | Height: | Size: 407 KiB |
BIN
docs/img/day2/run_app.gif
Normal file
|
After Width: | Height: | Size: 386 KiB |
BIN
docs/img/day2/warm_module.png
Normal file
|
After Width: | Height: | Size: 209 KiB |
BIN
docs/img/day2/y_is_false.gif
Normal file
|
After Width: | Height: | Size: 412 KiB |
BIN
docs/img/day3/api.gif
Normal file
|
After Width: | Height: | Size: 915 KiB |
BIN
docs/img/day3/index.gif
Normal file
|
After Width: | Height: | Size: 625 KiB |
BIN
docs/img/day3/install_requests.gif
Normal file
|
After Width: | Height: | Size: 258 KiB |
BIN
docs/img/day3/open_terminal.gif
Normal file
|
After Width: | Height: | Size: 770 KiB |
BIN
docs/img/day3/people.gif
Normal file
|
After Width: | Height: | Size: 591 KiB |
BIN
docs/img/day3/read_api.gif
Normal file
|
After Width: | Height: | Size: 738 KiB |
BIN
docs/img/day3/switch_term.gif
Normal file
|
After Width: | Height: | Size: 1.0 MiB |
BIN
docs/img/day5/clues.png
Normal file
|
After Width: | Height: | Size: 668 KiB |
BIN
docs/img/day5/config.gif
Normal file
|
After Width: | Height: | Size: 990 KiB |
BIN
docs/img/day5/copy.gif
Normal file
|
After Width: | Height: | Size: 933 KiB |
BIN
docs/img/day5/delete.gif
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
docs/img/day5/guesses.png
Normal file
|
After Width: | Height: | Size: 692 KiB |
BIN
docs/img/day5/main.png
Normal file
|
After Width: | Height: | Size: 578 KiB |
BIN
docs/img/day5/print.gif
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
docs/img/day5/requests.gif
Normal file
|
After Width: | Height: | Size: 3.2 MiB |
BIN
docs/img/day5/run.gif
Normal file
|
After Width: | Height: | Size: 768 KiB |
@@ -15,3 +15,28 @@
|
||||
|
||||
- The Interactive Python Prompt
|
||||
- A Python Program
|
||||
- A Django Project
|
||||
|
||||
### [Day 2](day2.md): not, and, or, if
|
||||
|
||||
- Back to the basics: and, or, not, if
|
||||
- Building a Terrible Weather App
|
||||
- Pulling it all together with some Django
|
||||
|
||||
### [Day 3](day3.md): for
|
||||
|
||||
- "For"
|
||||
- Creating an API
|
||||
- Reading an API with Python
|
||||
|
||||
### [Day 4](day4.md): while
|
||||
|
||||
- "While"
|
||||
- Let's build a menu
|
||||
- Threading
|
||||
|
||||
### [Day 5](day5.md): import
|
||||
|
||||
- "import"
|
||||
- Breaking apart our terrible weather app
|
||||
- Importing our menu
|
||||
58
ffmpeg.yaml
Normal file
@@ -0,0 +1,58 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ffmpeg
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ffmpeg
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ffmpeg
|
||||
spec:
|
||||
containers:
|
||||
- image: debian:latest
|
||||
name: ffmpeg
|
||||
command:
|
||||
- sleep
|
||||
- infinity
|
||||
volumeMounts:
|
||||
- mountPath: /in
|
||||
name: in
|
||||
- mountPath: /out
|
||||
name: out
|
||||
resources:
|
||||
limits:
|
||||
memory: "16Gi"
|
||||
cpu: "16"
|
||||
requests:
|
||||
memory: "1Mi"
|
||||
cpu: "1m"
|
||||
restartPolicy: Always
|
||||
volumes:
|
||||
- name: out
|
||||
persistentVolumeClaim:
|
||||
claimName: ffmpeg
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: ffmpeg-in
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 32Gi
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: ffmpeg-out
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteMany
|
||||
resources:
|
||||
requests:
|
||||
storage: 32Gi
|
||||
@@ -1,78 +1,36 @@
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-internal-tls
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik-internal
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
kubernetes.io/ingress.class: nginx
|
||||
name: {{ .Release.Name }}
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
rules:
|
||||
- host: {{ .Release.Name }}.ducoterra.net
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
service:
|
||||
name: {{ .Release.Name }}
|
||||
port:
|
||||
number: {{ .Values.port }}
|
||||
path: /
|
||||
pathType: Prefix
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
domains:
|
||||
- main: "*.ducoterra.net"
|
||||
routes:
|
||||
- match: Host(`{{ .Release.Name }}.ducoterra.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: {{ .Release.Name }}
|
||||
port: {{ .Values.port }}
|
||||
|
||||
- hosts:
|
||||
- {{ .Release.Name }}.ducoterra.net
|
||||
secretName: {{.Release.Name}}-tls-cert
|
||||
---
|
||||
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-internal-web
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik-internal
|
||||
name: {{.Release.Name}}.ducoterra.net
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`{{ .Release.Name }}.ducoterra.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: {{ .Release.Name }}
|
||||
port: {{ .Values.port }}
|
||||
middlewares:
|
||||
- name: httpsredirect
|
||||
|
||||
---
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-external-tls
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik-external
|
||||
spec:
|
||||
entryPoints:
|
||||
- websecure
|
||||
tls:
|
||||
certResolver: myresolver
|
||||
routes:
|
||||
- match: Host(`{{ .Release.Name }}.ducoterra.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: {{ .Release.Name }}
|
||||
port: {{ .Values.port }}
|
||||
|
||||
---
|
||||
|
||||
apiVersion: traefik.containo.us/v1alpha1
|
||||
kind: IngressRoute
|
||||
metadata:
|
||||
name: {{ .Release.Name }}-external-web
|
||||
annotations:
|
||||
kubernetes.io/ingress.class: traefik-external
|
||||
spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`{{ .Release.Name }}.ducoterra.net`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: {{ .Release.Name }}
|
||||
port: {{ .Values.port }}
|
||||
middlewares:
|
||||
- name: httpsredirect
|
||||
secretName: {{.Release.Name}}-tls-cert
|
||||
issuerRef:
|
||||
name: letsencrypt-prod
|
||||
kind: ClusterIssuer
|
||||
commonName: {{.Release.Name}}.ducoterra.net
|
||||
dnsNames:
|
||||
- {{.Release.Name}}.ducoterra.net
|
||||
|
||||
@@ -3,5 +3,14 @@ nav:
|
||||
- Home: index.md
|
||||
- Day 0: day0.md
|
||||
- Day 1: day1.md
|
||||
- Day 2: day2.md
|
||||
- Day 3: day3.md
|
||||
- Day 4: day4.md
|
||||
- Day 5: day5.md
|
||||
theme:
|
||||
name: material
|
||||
markdown_extensions:
|
||||
- pymdownx.keys
|
||||
- pymdownx.superfences
|
||||
- pymdownx.highlight:
|
||||
linenums_style: pymdownx.inline
|
||||
16
my_program.py
Normal file
@@ -0,0 +1,16 @@
|
||||
def print_hello():
|
||||
print('hello, world!')
|
||||
|
||||
def print_goodbye():
|
||||
print('goodbye!')
|
||||
|
||||
def middle_stuff():
|
||||
x = 1
|
||||
y = 2
|
||||
print(x + y)
|
||||
my_name = "Reese"
|
||||
print(my_name)
|
||||
|
||||
print_hello()
|
||||
middle_stuff()
|
||||
print_goodbye()
|
||||
1
setenv.sh
Executable file
@@ -0,0 +1 @@
|
||||
kubectl config set current-context k3os-alpha.dnet-ducoterra-websites
|
||||
51
weather_app.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import random
|
||||
|
||||
|
||||
warm = random.choice([True, False])
|
||||
cold = not warm
|
||||
raining = random.choice([True, False])
|
||||
snowing = not raining
|
||||
|
||||
if warm or cold:
|
||||
print("It's warm or snowing.")
|
||||
|
||||
if raining or warm:
|
||||
print("It's raining or warm.")
|
||||
|
||||
if raining or snowing:
|
||||
print("It's raining or cold.")
|
||||
|
||||
if cold or snowing:
|
||||
print("It's cold or snowing.")
|
||||
|
||||
warm_guess = input("Is it warm? (y/n) ")
|
||||
if warm_guess == 'y' and warm:
|
||||
print('Correct!')
|
||||
elif warm_guess == 'n' and not warm:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||
|
||||
cold_guess = input("Is it cold? (y/n) ")
|
||||
if cold_guess == 'y' and cold:
|
||||
print('Correct!')
|
||||
elif cold_guess == 'n' and not cold:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||
|
||||
raining_guess = input("Is it raining? (y/n) ")
|
||||
if raining_guess == 'y' and raining:
|
||||
print('Correct!')
|
||||
elif raining_guess == 'n' and not raining:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||
|
||||
snowing_guess = input("Is it snowing? (y/n) ")
|
||||
if snowing_guess == 'y' and snowing:
|
||||
print('Correct!')
|
||||
elif snowing_guess == 'n' and not snowing:
|
||||
print('Correct!')
|
||||
else:
|
||||
print('Wrong!')
|
||||