├── .gitignore
├── LICENSE.md
├── README.md
├── pyworkshop
├── .vscode
│ └── settings.json
├── 1_intro_python
│ ├── chapter2
│ │ └── exercise.py
│ ├── chapter3
│ │ └── exercise.py
│ ├── chapter4
│ │ ├── dicts_exercise.py
│ │ ├── lists_exercise.py
│ │ ├── mutability_exercise.py
│ │ ├── sets_excercise.py
│ │ └── tuples_exercise.py
│ ├── chapter5
│ │ └── exercise.py
│ ├── chapter6
│ │ └── exercise.py
│ ├── chapter7
│ │ ├── cities.json
│ │ ├── exceptions.py
│ │ ├── file_exercise.py
│ │ ├── hello.py
│ │ ├── mystery.py
│ │ ├── name.py
│ │ ├── name_lib.py
│ │ └── other_program.py
│ └── chapter8
│ │ ├── dog.py
│ │ └── exercise.py
└── 2_intermediate_python
│ ├── chapter1
│ └── exercise.py
│ ├── chapter2
│ └── exercise.py
│ ├── chapter3
│ ├── exercise_part1.py
│ ├── exercise_part2.py
│ ├── exercise_part3.py
│ └── gh_models.py
│ ├── chapter4
│ ├── exercise_part1_indentationerrors.py
│ ├── exercise_part2_syntaxerrors.py
│ ├── exercise_part3_zerodivision.py
│ ├── exercise_part4_custom_exceptions.py
│ ├── exercise_part5_try_except.py
│ ├── exercise_part6_reraising.py
│ └── gh_exceptions.py
│ ├── chapter5
│ └── exercise.py
│ ├── chapter6
│ ├── cli_exercise.py
│ ├── cli_exercise_input.py
│ └── optional_adv_exercise.py
│ ├── chapter7
│ ├── divisible.py
│ └── test_divisible.py
│ └── chapter8
│ ├── app.py
│ ├── repos
│ ├── __init__.py
│ ├── api.py
│ ├── exceptions.py
│ └── models.py
│ ├── requirements.txt
│ ├── static
│ ├── favicon.png
│ └── style.css
│ ├── static_files.zip
│ ├── templates
│ ├── error.html
│ └── index.html
│ ├── test.py
│ └── tests
│ ├── __init__.py
│ └── tests.py
└── website
├── .gitattributes
├── README.md
├── archetypes
└── default.md
├── config.toml
├── content
├── 01-introduction
│ ├── 00-who.md
│ ├── 02-navigating-course.md
│ ├── 02-requirements
│ │ ├── 05-vs-code
│ │ │ ├── 01-getting-started.md
│ │ │ ├── 03-working-with-python.md
│ │ │ ├── 04-the-repl-in-vscode.md
│ │ │ ├── 05-running-code.md
│ │ │ ├── _index.md
│ │ │ └── images
│ │ │ │ ├── command-palette.png
│ │ │ │ ├── install-circuitpy.mp4
│ │ │ │ ├── install-pylint.png
│ │ │ │ ├── interpreter.1.png
│ │ │ │ ├── interpreter.2.png
│ │ │ │ ├── open-folder.png
│ │ │ │ ├── popups copy.png
│ │ │ │ ├── popups.png
│ │ │ │ ├── repl-start.png
│ │ │ │ ├── repl.png
│ │ │ │ ├── select-linter.png
│ │ │ │ ├── select-pylint.png
│ │ │ │ ├── selected-interpreter.png
│ │ │ │ ├── vs-code-icon.png
│ │ │ │ ├── vs-code-logo.png
│ │ │ │ └── welcome-page.png
│ │ └── _index.md
│ ├── _index.md
│ └── images
│ │ ├── arrows.png
│ │ ├── clear_history.png
│ │ ├── copy.png
│ │ ├── edit-page.png
│ │ ├── expand-section.png
│ │ ├── header.png
│ │ ├── search.png
│ │ └── toc.png
├── 02-introduction-to-python
│ ├── 010-Best-Practices
│ │ ├── 01-anatomy-of-a-python-program.md
│ │ ├── 02-brief-history.md
│ │ ├── 03-conventions.md
│ │ └── _index.md
│ ├── 020-basic-data-types
│ │ ├── 00-variables.md
│ │ ├── 02-numbers.md
│ │ ├── 03-strings.md
│ │ ├── 05-common-string-and-number-errors.md
│ │ ├── 10-exercise.md
│ │ └── _index.md
│ ├── 060-functions
│ │ ├── 10-defining-functions.md
│ │ ├── 30-function-arguments.md
│ │ ├── 40-scope.md
│ │ ├── 50-exercise.md
│ │ └── _index.md
│ ├── 080-advanced-datatypes
│ │ ├── 10-lists.md
│ │ ├── 20-adding-removing-finding.md
│ │ ├── 30-tuples.md
│ │ ├── 50-sets.md
│ │ ├── 60-dictionaries.md
│ │ ├── 65-mutability.md
│ │ ├── 70-exercise.md
│ │ └── _index.md
│ ├── 090-boolean-logic
│ │ ├── 10-truthiness.md
│ │ ├── 20-comparisons.md
│ │ ├── 30-and-or-not.md
│ │ ├── 40-exercise.md
│ │ └── _index.md
│ ├── 110-control-statements-looping
│ │ ├── 05-looping-in-python.md
│ │ ├── 10-if-else-elif.md
│ │ ├── 30-while-loops.md
│ │ ├── 40-break-continue.md
│ │ ├── 50-exercise.md
│ │ ├── _index.md
│ │ ├── code
│ │ │ └── names.py
│ │ └── images
│ │ │ └── break-continue.png
│ ├── 175-running-code
│ │ ├── 10-running-python-programs.md
│ │ ├── 20-print-tips.md
│ │ ├── 30-the-main-method.md
│ │ ├── 50-exceptions.md
│ │ ├── 60-working-with-files.md
│ │ ├── 65-libraries.md
│ │ ├── 70-exercise.md
│ │ ├── _index.md
│ │ ├── code
│ │ │ ├── exceptions.py
│ │ │ ├── exceptions_one.py
│ │ │ ├── exceptions_two.py
│ │ │ ├── formatting_example.py
│ │ │ ├── hello.py
│ │ │ ├── mystery.py
│ │ │ ├── name.py
│ │ │ ├── name_lib.py
│ │ │ ├── name_lib_main.py
│ │ │ ├── other_program.py
│ │ │ ├── other_program_main.py
│ │ │ └── print_name.py
│ │ └── images
│ │ │ ├── .gitattributes
│ │ │ ├── terminal-drop-down-select.png
│ │ │ ├── terminal-drop-down.png
│ │ │ └── vs-code-run-file-command-palette.png
│ ├── 190-APIs
│ │ ├── 00-requests-and-responses.md
│ │ ├── 00-the-requests-library.md
│ │ ├── 00-what-is-an-API.md
│ │ ├── _index.md
│ │ ├── final-exercise.md
│ │ └── images
│ │ │ ├── 200.jpeg
│ │ │ ├── 301.jpeg
│ │ │ ├── 404.jpeg
│ │ │ ├── 500.jpeg
│ │ │ ├── Htcpcp_teapot.jpg
│ │ │ └── request-response.jpeg
│ ├── 200-conclusion
│ │ └── 00-wrapping-up.md
│ └── _index.md
├── 03-intermediate-python
│ ├── 00-final-project-preview.md
│ ├── 10-introduction
│ │ ├── 00-getting-ready.md
│ │ ├── 00-python-philosophy.md
│ │ ├── 15-converting-between-types
│ │ │ ├── 04-string-operations.md
│ │ │ ├── 10-exercise.md
│ │ │ └── _index.md
│ │ ├── _index.md
│ │ └── images
│ │ │ └── python.png
│ ├── 20-advanced-looping
│ │ ├── 10-list-comprehensions.md
│ │ ├── 30-other-comprehensions.md
│ │ ├── 50-slicing.md
│ │ ├── 70-zip.md
│ │ ├── 90-exercise.md
│ │ └── _index.md
│ ├── 30-oop-classes-inheritance
│ │ ├── 10-concept.md
│ │ ├── 30-classes.md
│ │ ├── 50-methods.md
│ │ ├── 70-inheritance.md
│ │ ├── 90-exercise.md
│ │ └── _index.md
│ ├── 40-exceptions
│ │ ├── 10-all-about-exceptions.md
│ │ ├── 30-try-except-else-finally.md
│ │ ├── 50-exception-hierarchy.md
│ │ ├── 70-best-practices.md
│ │ ├── 90-custom-exceptions.md
│ │ ├── 99-exercise.md
│ │ └── _index.md
│ ├── 50-libraries-modules
│ │ ├── 10-standard-library.md
│ │ ├── 30-modules-and-imports.md
│ │ ├── 50-pypi.md
│ │ ├── 90-exercise.md
│ │ └── _index.md
│ ├── 60-command-line-tools
│ │ ├── 10-advanced-strings.md
│ │ ├── 30-accepting-user-input.md
│ │ ├── 90-exercise.md
│ │ └── _index.md
│ ├── 70-tests
│ │ ├── 10-concept.md
│ │ ├── 30-assertions.md
│ │ ├── 50-writing-tests.md
│ │ ├── 90-exercise.md
│ │ └── _index.md
│ ├── 80-web-frameworks
│ │ ├── _index.md
│ │ ├── basic-flask.md
│ │ ├── final-exercise.md
│ │ └── images
│ │ │ └── request-response.jpeg
│ ├── 90-Conclusion
│ │ └── _index.md
│ └── _index.md
├── _index.md
└── credits.md
├── layouts
├── partials
│ ├── logo.html
│ ├── menu-footer.html
│ └── meta_twitter.html
└── shortcodes
│ └── todo.html
├── public
├── categories
│ └── index.xml
├── index.xml
├── sitemap.xml
└── tags
│ └── index.xml
├── static
├── _redirects
├── code
│ ├── cities.json
│ ├── day_one_class.py
│ ├── day_one_min.py
│ ├── day_two_final_exercise.zip
│ ├── day_two_final_exercise
│ │ ├── app.py
│ │ ├── repos
│ │ │ ├── __init__.py
│ │ │ ├── api.py
│ │ │ ├── exceptions.py
│ │ │ └── models.py
│ │ ├── requirements.txt
│ │ ├── static
│ │ │ ├── favicon.png
│ │ │ └── style.css
│ │ ├── static_files.zip
│ │ ├── templates
│ │ │ ├── error.html
│ │ │ └── index.html
│ │ ├── test.py
│ │ └── tests
│ │ │ ├── __init__.py
│ │ │ └── tests.py
│ ├── dayone.py
│ └── daytwo_part1.py
└── images
│ ├── favicon.png
│ ├── fem.png
│ ├── me.jpg
│ ├── snake-cropped.png
│ ├── snake-scaled.png
│ ├── snake.png
│ └── twittercard.png
└── themes
└── nnja-theme-learn
├── .gitignore
├── .grenrc.yml
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── archetypes
├── chapter.md
└── default.md
├── i18n
├── en.toml
├── es.toml
├── fr.toml
├── id.toml
├── nl.toml
├── pt.toml
└── tr.toml
├── images
├── screenshot.png
└── tn.png
├── layouts
├── 404.html
├── _default
│ ├── list.html
│ └── single.html
├── index.html
├── index.json
├── partials
│ ├── custom-comments.html
│ ├── custom-footer.html
│ ├── custom-header.html
│ ├── favicon.html
│ ├── footer.html
│ ├── header.html
│ ├── logo.html
│ ├── menu-footer.html
│ ├── menu.html
│ ├── meta.html
│ ├── search.html
│ └── toc.html
└── shortcodes
│ ├── attachments.html
│ ├── button.html
│ ├── children.html
│ ├── expand.html
│ ├── mermaid.html
│ ├── notice.html
│ ├── ref.html
│ ├── relref.html
│ └── siteparam.html
├── netlify.toml
├── static
├── css
│ ├── auto-complete.css
│ ├── featherlight.min.css
│ ├── fontawesome-all.min.css
│ ├── hugo-theme.css
│ ├── hybrid-theme-purple.css
│ ├── hybrid.css
│ ├── nucleus.css
│ ├── perfect-scrollbar.min.css
│ ├── theme-blue.css
│ ├── theme-green.css
│ ├── theme-red.css
│ └── theme.css
├── fonts
│ ├── Inconsolata.eot
│ ├── Inconsolata.svg
│ ├── Inconsolata.ttf
│ ├── Inconsolata.woff
│ ├── Novecentosanswide-Normal-webfont.eot
│ ├── Novecentosanswide-Normal-webfont.svg
│ ├── Novecentosanswide-Normal-webfont.ttf
│ ├── Novecentosanswide-Normal-webfont.woff
│ ├── Novecentosanswide-Normal-webfont.woff2
│ ├── Novecentosanswide-UltraLight-webfont.eot
│ ├── Novecentosanswide-UltraLight-webfont.svg
│ ├── Novecentosanswide-UltraLight-webfont.ttf
│ ├── Novecentosanswide-UltraLight-webfont.woff
│ ├── Novecentosanswide-UltraLight-webfont.woff2
│ ├── Work_Sans_200.eot
│ ├── Work_Sans_200.svg
│ ├── Work_Sans_200.ttf
│ ├── Work_Sans_200.woff
│ ├── Work_Sans_200.woff2
│ ├── Work_Sans_300.eot
│ ├── Work_Sans_300.svg
│ ├── Work_Sans_300.ttf
│ ├── Work_Sans_300.woff
│ ├── Work_Sans_300.woff2
│ ├── Work_Sans_500.eot
│ ├── Work_Sans_500.svg
│ ├── Work_Sans_500.ttf
│ ├── Work_Sans_500.woff
│ └── Work_Sans_500.woff2
├── images
│ ├── clippy.svg
│ ├── favicon.png
│ └── gopher-404.jpg
├── js
│ ├── auto-complete.js
│ ├── clipboard.min.js
│ ├── featherlight.min.js
│ ├── highlight.pack.js
│ ├── html5shiv-printshiv.min.js
│ ├── hugo-learn.js
│ ├── jquery-2.x.min.js
│ ├── jquery.sticky.js
│ ├── learn.js
│ ├── lunr.min.js
│ ├── modernizr.custom.71422.js
│ ├── perfect-scrollbar.jquery.min.js
│ ├── perfect-scrollbar.min.js
│ └── search.js
├── mermaid
│ ├── mermaid.css
│ ├── mermaid.dark.css
│ ├── mermaid.forest.css
│ └── mermaid.js
└── webfonts
│ ├── fa-brands-400.eot
│ ├── fa-brands-400.svg
│ ├── fa-brands-400.ttf
│ ├── fa-brands-400.woff
│ ├── fa-brands-400.woff2
│ ├── fa-regular-400.eot
│ ├── fa-regular-400.svg
│ ├── fa-regular-400.ttf
│ ├── fa-regular-400.woff
│ ├── fa-regular-400.woff2
│ ├── fa-solid-900.eot
│ ├── fa-solid-900.svg
│ ├── fa-solid-900.ttf
│ ├── fa-solid-900.woff
│ └── fa-solid-900.woff2
└── theme.toml
/.gitignore:
--------------------------------------------------------------------------------
1 | #### Python Section
2 |
3 | # Byte-compiled / optimized / DLL files
4 | __pycache__/
5 | *.py[cod]
6 | *$py.class
7 |
8 | # C extensions
9 | *.so
10 |
11 | # Distribution / packaging
12 | .Python
13 | build/
14 | develop-eggs/
15 | dist/
16 | downloads/
17 | eggs/
18 | .eggs/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | wheels/
25 | pip-wheel-metadata/
26 | share/python-wheels/
27 | *.egg-info/
28 | .installed.cfg
29 | *.egg
30 | MANIFEST
31 |
32 | # PyInstaller
33 | # Usually these files are written by a python script from a template
34 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
35 | *.manifest
36 | *.spec
37 |
38 | # Installer logs
39 | pip-log.txt
40 | pip-delete-this-directory.txt
41 |
42 | # Unit test / coverage reports
43 | htmlcov/
44 | .tox/
45 | .nox/
46 | .coverage
47 | .coverage.*
48 | .cache
49 | nosetests.xml
50 | coverage.xml
51 | *.cover
52 | .hypothesis/
53 | .pytest_cache/
54 |
55 | # Translations
56 | *.mo
57 | *.pot
58 |
59 | # Django stuff:
60 | *.log
61 | local_settings.py
62 | db.sqlite3
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | target/
76 |
77 | # Jupyter Notebook
78 | .ipynb_checkpoints
79 |
80 | # IPython
81 | profile_default/
82 | ipython_config.py
83 |
84 | # pyenv
85 | .python-version
86 |
87 | # pipenv
88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
90 | # having no cross-platform support, pipenv may install dependencies that don’t work, or not
91 | # install all needed dependencies.
92 | #Pipfile.lock
93 |
94 | # celery beat schedule file
95 | celerybeat-schedule
96 |
97 | # SageMath parsed files
98 | *.sage.py
99 |
100 | # Environments
101 | .env
102 | .venv
103 | env/
104 | venv/
105 | ENV/
106 | env.bak/
107 | venv.bak/
108 |
109 | # Spyder project settings
110 | .spyderproject
111 | .spyproject
112 |
113 | # Rope project settings
114 | .ropeproject
115 |
116 | # mkdocs documentation
117 | /site
118 |
119 | # mypy
120 | .mypy_cache/
121 | .dmypy.json
122 | dmypy.json
123 |
124 | # Pyre type checker
125 | .pyre/
126 |
127 | # VS Code Settings
128 | .vscode/
129 |
130 |
131 | #### MacOs Section
132 |
133 | # General
134 | .DS_Store
135 | .AppleDouble
136 | .LSOverride
137 |
138 | # Icon must end with two \r
139 | Icon
140 |
141 | # Thumbnails
142 | ._*
143 |
144 | # Files that might appear in the root of a volume
145 | .DocumentRevisions-V100
146 | .fseventsd
147 | .Spotlight-V100
148 | .TemporaryItems
149 | .Trashes
150 | .VolumeIcon.icns
151 | .com.apple.timemachine.donotpresent
152 |
153 | # Directories potentially created on remote AFP share
154 | .AppleDB
155 | .AppleDesktop
156 | Network Trash Folder
157 | Temporary Items
158 | .apdisk
159 |
160 | #### Hugo Section
161 |
162 | # generated files by hugo
163 | docs/
164 | /public/
165 | /resources/_gen/
166 |
167 | # executable may be added to repository
168 | hugo.exe
169 | hugo.darwin
170 | hugo.linux
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2018 GitHub, Inc. and contributors
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Frontend Masters - Fundamentals & Intermediate Python Courses
2 |
3 | These are the resources for Nina Zakharenko's Python Fundamentals and Intermediate Python Courses
4 |
5 | * [Watch Python Fundamentals on Frontend Masters](https://frontendmasters.com/courses/python/)
6 |
7 | The majority of the content can be found on the course website.
8 |
9 | * [Course Website - https://www.learnpython.dev](https://www.learnpython.dev)
10 | * [This Repo - git.io/python3](https://git.io/python3)
11 | * [Follow Nina on Twitter](https://twitter.com/nnja)
12 |
13 | ## License
14 |
15 | The content of this project itself is licensed under the [Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International (CC BY-NC-ND 4.0) license](https://creativecommons.org/licenses/by-nc-nd/4.0/), and the underlying source code used to format and display that content, along with the code exercises is licensed under the [MIT license](LICENSE.md).
--------------------------------------------------------------------------------
/pyworkshop/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "python.pythonPath": "env/bin/python3"
3 | }
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter2/exercise.py:
--------------------------------------------------------------------------------
1 | # Part 1
2 | x = 42
3 | type(x)
4 |
5 | y = 3 / 4
6 | type(y)
7 |
8 | z = int('7')
9 | type(z)
10 |
11 | a = float(5)
12 | type(a)
13 |
14 | name = "Nina"
15 | type(name)
16 |
17 | # Part 2
18 | rent = 480
19 | per_day = rent / 30
20 | print(per_day)
21 |
22 | # Part 3
23 | print("Hello world")
24 | name = "Nina"
25 | print("My name is", name)
26 |
27 | name = "Nina"
28 | print("Hello, my name is %s" % name)
29 |
30 | name = "Nina"
31 | print(f"Hello, my name is {name} and I pay ${rent / 30} in rent per day")
32 |
33 | # Part 4
34 | x = 42
35 | y = 3 / 4
36 | name = "Nina"
37 | type(x)
38 | type(y)
39 | type(name)
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter3/exercise.py:
--------------------------------------------------------------------------------
1 | # Part 1 - Basic Functions
2 |
3 | def add_numbers(x, y):
4 | return x + y
5 |
6 |
7 | add_numbers(1, 2)
8 | print(f"The product of 1 and 2 is {add_numbers(1, 2)}")
9 |
10 | # Function Scope
11 | x = 1
12 | y = 2
13 |
14 | def add_numbers(x, y):
15 | print(f"Inside the function, x = {x} and y = {y}")
16 | return x + y
17 |
18 | print(f"Outside the function, x = {x} and y = {y}")
19 | print(f"The product of 5 and 6 is {add_numbers(5, 6)}")
20 |
21 | # Positional vs Keyword Arguments
22 | def calculate_numbers(x, y, operation="add"):
23 | if operation == "add":
24 | return x + y
25 | elif operation == "subtract":
26 | return x - y
27 | calculate_numbers(2, 3)
28 | calculate_numbers(2, 3, "subtract")
29 | calculate_numbers(2, 3, operation="subtract")
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter4/dicts_exercise.py:
--------------------------------------------------------------------------------
1 | # Remember, dictionaries don't have numerical indexes
2 | # like lists, so if you try to use an index number...
3 | # Unless 0 happens to be a key.
4 | my_dict = {"key": "value"}
5 | my_dict[0]
6 |
7 | my_dict["hello"] = "world"
8 | my_dict["foo"] = "bar"
9 | my_dict
10 | my_dict["hello"]
11 | my_dict.get("hello")
12 | my_dict["baz"]
13 | "baz" in my_dict
14 | my_dict.get("baz", "boo")
15 | my_dict.keys()
16 | my_dict.values()
17 | my_dict.items()
18 |
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter4/lists_exercise.py:
--------------------------------------------------------------------------------
1 | # Part 1
2 |
3 | my_list = ["h", "e", "l", "l", "o"]
4 | my_list
5 | my_list.append("!")
6 | my_list
7 |
8 | # Slicing
9 |
10 | len(my_list)
11 | my_list[4:6]
12 | my_list[4:]
13 | my_list[-2:]
14 |
15 | # Lists - Adding to and removing
16 |
17 | my_list.remove("l")
18 | my_list.insert(2, "l")
19 | del my_list[0]
20 | last_item = my_list.pop()
21 | last_item
22 | my_list[2]
23 | "!" in my_list
24 | my_list.sort(reverse=True)
25 | my_list
26 | sorted(my_list, reverse=False)
27 | my_list
28 |
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter4/mutability_exercise.py:
--------------------------------------------------------------------------------
1 | # Lists are mutable
2 | my_list = [1, 2, 3]
3 | my_list[0] = 'a'
4 | my_list
5 |
6 | # Dictionaries are also mutable
7 | my_dict = {"hello": "world"}
8 | my_dict["foo"] = "bar"
9 | my_dict
10 |
11 | # Sets are mutable, but don't support
12 | # indexing or item assignment,
13 | # so you have to use add() and remove()
14 | my_set = {1, 2, 3}
15 | my_set[0] = 'a' # This will throw a TypeError
16 | my_set.add('a')
17 | my_set
18 |
19 | # Tuples are immutable
20 | my_tuple = (1, 2, 3)
21 | my_tuple[0] = 'a' # This will throw a TypeError
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter4/sets_excercise.py:
--------------------------------------------------------------------------------
1 | my_set = {}
2 | type(my_set)
3 | my_set = set()
4 | my_set
5 | my_set = {1, 2, 3}
6 | my_set.add(4)
7 | my_set.remove(2)
8 | 2 in my_set
9 | my_set
10 | my_set.add(3)
11 | my_set
12 | my_set
13 | my_other_set = {1, 2, 3}
14 | my_set.union(my_other_set)
15 | my_set.intersection(my_other_set)
16 | my_set.difference(my_other_set)
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter4/tuples_exercise.py:
--------------------------------------------------------------------------------
1 | # Part 1
2 |
3 | my_tuple = 1,
4 | my_tuple
5 | my_tuple[1] = 2
6 |
7 | # Part 2 - Will Throw an Error
8 | # TypeError: 'tuple' object does not support item assignment
9 |
10 | person = ('Jim', 29, 'Austin, TX')
11 | name, age, hometown = person
12 | name
13 | age
14 | hometown
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter5/exercise.py:
--------------------------------------------------------------------------------
1 | # Part 1
2 |
3 | 10 > 5
4 | 5 > 10
5 | 10 > 10
6 | 10 >= 10
7 | 5 < 10
8 | 5 < 5
9 | 5 <= 5
10 | 5 == 5
11 | 5 != 10
12 |
13 | # Part 2
14 |
15 | 5 == True
16 | # The number 5 does not equal True, but...
17 | if 5:
18 | print("The number 5 is truthy!")
19 | # The number 5 is truthy for an if test!
20 |
21 | # Part 3
22 |
23 | 1 == True
24 | 0 == False
25 |
26 | # Part 4
27 |
28 | True or False
29 | [] or [1, 2, 3]
30 | "Hello" or None
31 |
32 | True and False
33 | 5 and 0
34 | [1] and [1, 2, 3]
35 | "Hello" and None
36 |
37 | # Of course, you can use `and` and `or` aren't limited to two operands
38 | a = False
39 | b = False
40 | c = False
41 | a or b or c
42 | b = True
43 | a or b or c
44 | a and b and c
45 | a = True
46 | c = True
47 | a and b and c
48 |
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/cities.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "New York",
3 | "pop": 8550405
4 | },
5 | {
6 | "name": "Los Angeles",
7 | "pop": 3971883
8 | },
9 | {
10 | "name": "Chicago",
11 | "pop": 2720546
12 | },
13 | {
14 | "name": "Houston",
15 | "pop": 2296224
16 | },
17 | {
18 | "name": "Philadelphia",
19 | "pop": 1567442
20 | }
21 | ]
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/exceptions.py:
--------------------------------------------------------------------------------
1 | # this will throw an error
2 | try:
3 | int("a")
4 | except ValueError as e:
5 | print("oops, you can't do that!", e)
6 |
7 | print("this is the end of my program")
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/file_exercise.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | def main():
4 | with open("cities.json") as cities_file:
5 | try:
6 | cities_data = json.load(cities_file)
7 |
8 | print("Largest cities in the US by population:")
9 | for index, entry in enumerate(cities_data):
10 | print(f"{index + 1}: {entry['name']} - {entry['pop']}")
11 | list
12 | except json.decoder.JSONDecodeError as error:
13 | print("Sorry, there was an error decoding that json file:")
14 | print(f"\t {error}")
15 |
16 | print("The file is now closed.")
17 |
18 | if __name__ == "__main__":
19 | main()
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/hello.py:
--------------------------------------------------------------------------------
1 | greetings = ["Hello", "Bonjour", "Hola"]
2 |
3 | for greeting in greetings:
4 | print(f"{greeting}, World!")
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/mystery.py:
--------------------------------------------------------------------------------
1 | def mystery():
2 | num = 10 * 3
3 |
4 | if num == 10:
5 | print("condition 10")
6 | num = num * 10
7 | elif num == 30:
8 | print("condition 30")
9 | num = num * 30
10 |
11 | print(f"num was {num}")
12 | return num
13 |
14 | print(mystery())
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/name.py:
--------------------------------------------------------------------------------
1 | name = "Nina"
2 | print(name)
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/name_lib.py:
--------------------------------------------------------------------------------
1 | def upper_case_name(name):
2 | return name.upper()
3 |
4 | if __name__ == "__main__":
5 | name = "Nina"
6 | name_upper = upper_case_name(name)
7 | print(f"Upper case name is {name_upper}")
8 | print("dunder name", __name__)
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter7/other_program.py:
--------------------------------------------------------------------------------
1 | import name_lib
2 |
3 | my_name = "Fred"
4 | upper_name = name_lib.upper_case_name(my_name)
5 |
6 | print(f"In my own code, upper name is {upper_name}")
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter8/dog.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | api_url = "http://shibe.online/api/shibes?count=1"
4 |
5 | params = {"count": 10}
6 | response = requests.get(api_url, params=params)
7 |
8 | status_code = response.status_code
9 | print("status code: ", status_code)
10 |
11 | response_json = response.json()
12 | print(response_json)
13 | print(response.url)
--------------------------------------------------------------------------------
/pyworkshop/1_intro_python/chapter8/exercise.py:
--------------------------------------------------------------------------------
1 | """
2 | TIP: Don't forget to run: pip install requests!
3 |
4 | A small Python program that uses the GitHub search API to list
5 | the top projects by language, based on stars.
6 |
7 | GitHub Search API documentation: https://developer.github.com/v3/search/
8 |
9 | Additional parameters for searching repos can be found here:
10 | https://help.github.com/en/articles/searching-for-repositories#search-by-number-of-stars
11 |
12 | Note: The API will return results found before a timeout occurs,
13 | so results may not be the same across requests, even with the same query.
14 |
15 | Requests to this endpoint are rate limited to 10 requests per
16 | minute per IP address.
17 | """
18 |
19 | import requests
20 |
21 | GITHUB_API_URL = "https://api.github.com/search/repositories"
22 |
23 |
24 | def create_query(languages, min_stars=50000):
25 | """
26 | Create the query string for the GitHub search API,
27 | based on the minimum amount of stars for a project, and
28 | the provided programming languages.
29 |
30 | An example search query looks like:
31 | stars:>50000 language:python language:javascript
32 | """
33 | query = f"stars:>{min_stars} "
34 |
35 | for language in languages:
36 | query += f"language:{language} "
37 |
38 | return query
39 |
40 |
41 | def repos_with_most_stars(languages, sort="stars", order="desc"):
42 | query = create_query(languages)
43 |
44 | # Define the parameters we want to be part of our URL
45 | parameters = {"q": query, "sort": sort, "order": order}
46 |
47 | # Pass in the query and the parameters as part of the request.
48 | response = requests.get(GITHUB_API_URL, params=parameters)
49 | status_code = response.status_code
50 |
51 | # Check if the rate limit was hit. Applies only for students running this code
52 | # in the in-person course.
53 | if status_code == 403:
54 | raise RuntimeError("Rate limit reached. Please wait a minute and try again.")
55 | if status_code != 200:
56 | raise RuntimeError(f"An error occurred. HTTP Status Code was: {status_code}.")
57 | else:
58 | response_json = response.json()
59 | records = response_json["items"]
60 | return records
61 |
62 |
63 | if __name__ == "__main__":
64 | languages = ["python", "javascript", "ruby"]
65 | results = repos_with_most_stars(languages)
66 |
67 | for result in results:
68 | language = result["language"]
69 | stars = result["stargazers_count"]
70 | name = result["name"]
71 |
72 | print(f"-> {name} is a {language} repo with {stars} stars.")
73 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter1/exercise.py:
--------------------------------------------------------------------------------
1 | my_string = str(100)
2 | my_string
3 | type(my_string)
4 |
5 | my_int = int(my_string)
6 | print(my_int)
7 | type(my_int)
8 |
9 | float("3.1415")
10 | int(3.1415)
11 |
12 | # Converting between lists and strings
13 | my_list = list("hello")
14 | print(my_list)
15 | str(my_list)
16 |
17 | # String join method
18 | ''.join(my_list)
19 | ','.join(my_list)
20 | '-'.join(my_list)
21 |
22 | # String split
23 | my_string = "the,quick,brown,fox"
24 | my_string.split(",")
25 |
26 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter2/exercise.py:
--------------------------------------------------------------------------------
1 | # Comprehensions
2 | my_list = [num for num in range(0, 100) if num % 2 == 0]
3 | print(my_list)
4 |
5 | import random
6 | my_dict = {num:random.randint(0, 100) for num in my_list}
7 | print(my_dict)
8 |
9 | my_set = {num for num in my_dict.values()}
10 | print(my_set)
11 |
12 | # Slicing
13 | my_list = [num for num in range(0, 100)]
14 | my_slice = my_list[30:70:2]
15 | print(my_slice)
16 |
17 | my_backwards_slice = my_slice[::-1]
18 | print(my_backwards_slice)
19 |
20 | # Zip
21 | names = ["Nina", "Max", "Floyd", "Lloyd"]
22 | scores = [random.randint(0, 100) for name in names]
23 | print(scores)
24 |
25 | for name, score in zip(names, scores):
26 | print(f"{name} got a score of {score}")
27 |
28 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter3/exercise_part1.py:
--------------------------------------------------------------------------------
1 | class Vehicle:
2 |
3 | def __init__(self, make, model, fuel="gas"):
4 | self.make = make
5 | self.model = model
6 | self.fuel = fuel
7 |
8 | daily_driver = Vehicle("Subaru", "Crosstrek")
9 | # By default, this is how python represents our object:
10 | print(daily_driver)
11 |
12 | # The variables we saved to the instance are available like this:
13 | print(f"I drive a {daily_driver.make} {daily_driver.model}. It runs on {daily_driver.fuel}.")
14 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter3/exercise_part2.py:
--------------------------------------------------------------------------------
1 | class Vehicle:
2 |
3 | number_of_wheels = 4
4 |
5 | def __init__(self, make, model, fuel="gas"):
6 | self.make = make
7 | self.model = model
8 | self.fuel = fuel
9 |
10 | daily_driver = Vehicle("Subaru", "Crosstrek")
11 |
12 | daily_driver.number_of_wheels = 3
13 |
14 | # Instance variables
15 | print(f"I drive a {daily_driver.make} {daily_driver.model}. It runs on {daily_driver.fuel}.")
16 | print(f"My {daily_driver.model} has {daily_driver.number_of_wheels} wheels.")
17 |
18 | # Class variable
19 | print(f"Most vehicles have {Vehicle.number_of_wheels} wheels.")
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter3/exercise_part3.py:
--------------------------------------------------------------------------------
1 | class Vehicle:
2 |
3 | def __init__(self, make, model, fuel="gas"):
4 | self.make = make
5 | self.model = model
6 | self.fuel = fuel
7 |
8 |
9 | class Car(Vehicle):
10 |
11 | number_of_wheels = 4
12 |
13 |
14 | class Truck(Vehicle):
15 |
16 | number_of_wheels = 6
17 |
18 | def __init__(self, make, model, fuel="diesel"):
19 | super().__init__(make, model, fuel)
20 |
21 |
22 | daily_driver = Car("Subaru", "Crosstrek")
23 | print(f"I drive a {daily_driver.make} {daily_driver.model}. "
24 | f"It uses {daily_driver.fuel} and has {daily_driver.number_of_wheels} wheels.")
25 |
26 | truck = Truck("Ford", "F350")
27 | print(f"I also have a {truck.make} {truck.model}. "
28 | f"It uses {truck.fuel} and has {truck.number_of_wheels} wheels.")
29 |
30 | print(
31 | f"My daily driver is a {type(daily_driver)} and my truck is a {type(truck)}")
32 |
33 | print(f"Is my daily driver a car? {isinstance(daily_driver, Car)}")
34 | print(f"Is my truck a Vehicle? {isinstance(truck, Vehicle)}")
35 | print(f"Is my truck a Car? {isinstance(truck, Car)}")
36 |
37 | print(f"Is a Truck a subclass of Vehicle? {issubclass(Truck, Vehicle)}")
38 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter3/gh_models.py:
--------------------------------------------------------------------------------
1 | class GitHubRepo:
2 |
3 | def __init__(self, name, language, num_stars):
4 | self.name = name
5 | self.language = language
6 | self.num_stars = num_stars
7 |
8 | def __str__(self):
9 | return f"-> {self.name} is a {self.language} repo with {self.num_stars} stars."
10 |
11 | def __repr__(self):
12 | return f'GitHubRepo({self.name}, {self.language}, {self.num_stars})'
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter4/exercise_part1_indentationerrors.py:
--------------------------------------------------------------------------------
1 | def my_function():
2 | print("Hello!")
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter4/exercise_part2_syntaxerrors.py:
--------------------------------------------------------------------------------
1 | a = [4,
2 | x = 5
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter4/exercise_part3_zerodivision.py:
--------------------------------------------------------------------------------
1 | # Will cause a ZeroDivisionError
2 | a = 1 / 0
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter4/exercise_part4_custom_exceptions.py:
--------------------------------------------------------------------------------
1 | class MyException(Exception):
2 | def __init__(self, message):
3 | new_message = f"!!!ERROR!!! {message}"
4 | super().__init__(new_message)
5 |
6 | raise MyException("Something went wrong!")
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter4/exercise_part5_try_except.py:
--------------------------------------------------------------------------------
1 | try:
2 | my_dict = {"hello": "world"}
3 | print(my_dict["foo"])
4 | except KeyError:
5 | print("Oh no! That key doesn't exist")
6 |
7 | try:
8 | my_dict = {"hello": "world"}
9 | print(my_dict["foo"])
10 | except KeyError as key_error:
11 | print(f"Oh no! The key {key_error} doesn't exist!")
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter4/exercise_part6_reraising.py:
--------------------------------------------------------------------------------
1 | while True:
2 | for divisor in range(5, -1, -1):
3 | try:
4 | quotient = 10 / divisor
5 | print(f"10 / {divisor} = {quotient}")
6 | except ZeroDivisionError:
7 | print("Oops! We tried to divide by zero!")
8 | raise RuntimeError
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter4/gh_exceptions.py:
--------------------------------------------------------------------------------
1 | """
2 | GitHub API Application: Custom Exception Classes
3 | """
4 |
5 | class GitHubApiException(Exception):
6 |
7 | def __init__(self, status_code):
8 | if status_code == 403:
9 | message = "Rate limit reached. Please wait a minute and try again."
10 | else:
11 | message = f"HTTP Status Code was: {status_code}."
12 |
13 | super().__init__(message)
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter5/exercise.py:
--------------------------------------------------------------------------------
1 |
2 | # Using os
3 | import os
4 |
5 | my_folder = os.getcwd()
6 | print(f"Here are the files in {my_folder}:")
7 |
8 | with os.scandir(my_folder) as folder:
9 | for entry in folder:
10 | print(f" - {entry.name}")
11 |
12 | # Using sys
13 |
14 | import sys
15 |
16 | arguments = sys.argv
17 | print(f"We received the following arguments:")
18 |
19 | for arg in arguments:
20 | print(f" - {arg}")
21 |
22 | print(f"We are running on a '{sys.platform}' machine")
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter6/cli_exercise.py:
--------------------------------------------------------------------------------
1 | import sys
2 |
3 | args = sys.argv
4 |
5 | print(args)
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter6/cli_exercise_input.py:
--------------------------------------------------------------------------------
1 | name = input("Hello, what is your name? ")
2 |
3 | birthday_string = input(f"Hello {name.strip()}. Please enter your birthday in MM/DD/YYYY format: ")
4 |
5 | print(f"Hello {name}. Your birthday is on {birthday_string}.")
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter7/divisible.py:
--------------------------------------------------------------------------------
1 | def divisible_by(check_number, divisor):
2 | return check_number % divisor == 0
3 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter7/test_divisible.py:
--------------------------------------------------------------------------------
1 | import unittest
2 | from divisible import divisible_by
3 |
4 | class TestCase(unittest.TestCase):
5 |
6 | def test_divisible_by(self):
7 | self.assertTrue(divisible_by(10, 2))
8 | self.assertTrue(divisible_by(10, 3))
9 |
10 |
11 | if __name__ == '__main__':
12 | unittest.main()
13 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/app.py:
--------------------------------------------------------------------------------
1 | """
2 | A Simple Flask Web Application interface
3 | For viewing popular GitHub Repos sorted by stars using the
4 | GitHub Search API.
5 |
6 | To run:
7 | (env) $ python -m pip install -r requirements.txt
8 | (env) $ export FLASK_ENV=development; python3 -m flask run
9 | """
10 | from flask import Flask, render_template, request
11 |
12 | from repos.api import repos_with_most_stars
13 | from repos.exceptions import GitHubApiException
14 |
15 | app = Flask(__name__)
16 |
17 | available_languages = ["Python", "JavaScript", "Ruby", "Java"]
18 |
19 |
20 | @app.route('/', methods=['POST', 'GET'])
21 | def index():
22 | if request.method == 'GET':
23 | # Use the list of all languages
24 | selected_languages = available_languages
25 | elif request.method == 'POST':
26 | # Use the languages we selected in the request form
27 | selected_languages = request.form.getlist("languages")
28 |
29 | results = repos_with_most_stars(selected_languages)
30 |
31 | return render_template(
32 | 'index.html',
33 | selected_languages=selected_languages,
34 | available_languages=available_languages,
35 | results=results)
36 |
37 |
38 | @app.errorhandler(GitHubApiException)
39 | def handle_api_error(error):
40 | return render_template('error.html', message=error)
41 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/repos/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/pyworkshop/2_intermediate_python/chapter8/repos/__init__.py
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/repos/api.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | from repos.exceptions import GitHubApiException
4 | from repos.models import GitHubRepo
5 |
6 |
7 | GITHUB_API_URL = "https://api.github.com/search/repositories"
8 |
9 |
10 | def create_query(languages, min_stars):
11 | """
12 | Create the query string for the GitHub search API,
13 | based on the minimum amount of stars for a project, and
14 | the provided programming languages.
15 | """
16 | # Notice we are calling .strip() on each language,
17 | # to clear it of leading and trailing whitespace
18 | query = " ".join(f"language:{language.strip()}" for language in languages)
19 | query = query + f" stars:>{min_stars}"
20 | return query
21 |
22 |
23 | def repos_with_most_stars(languages, min_stars=40000, sort="stars", order="desc"):
24 | query = create_query(languages, min_stars)
25 | parameters = {"q": query, "sort": sort, "order": order}
26 | print(parameters)
27 | response = requests.get(GITHUB_API_URL, params=parameters)
28 |
29 | if response.status_code != 200:
30 | raise GitHubApiException(response.status_code)
31 |
32 | response_json = response.json()
33 | items = response_json["items"]
34 | return [GitHubRepo(item["name"], item["language"], item["stargazers_count"]) for item in items]
35 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/repos/exceptions.py:
--------------------------------------------------------------------------------
1 | """
2 | GitHub API Application: Custom Exception Classes
3 | """
4 |
5 | class GitHubApiException(Exception):
6 |
7 | def __init__(self, status_code):
8 | if status_code == 403:
9 | message = "Rate limit reached. Please wait a minute and try again."
10 | else:
11 | message = f"HTTP Status Code was: {status_code}."
12 |
13 | super().__init__("A GitHub API Error Occurred: " + message)
14 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/repos/models.py:
--------------------------------------------------------------------------------
1 | """
2 | GitHub API Application: Custom Model Classes
3 | """
4 |
5 | class GitHubRepo:
6 | """
7 | A class used to represent a single GitHub Repository.
8 | """
9 |
10 | def __init__(self, name, language, num_stars):
11 | self.name = name
12 | self.language = language
13 | self.num_stars = num_stars
14 |
15 | def __str__(self):
16 | return f"-> {self.name} is a {self.language} repo with {self.num_stars} stars."
17 |
18 | def __repr__(self):
19 | return f'GitHubRepo({self.name}, {self.language}, {self.num_stars})'
20 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | requests
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/pyworkshop/2_intermediate_python/chapter8/static/favicon.png
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/static_files.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/pyworkshop/2_intermediate_python/chapter8/static_files.zip
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/templates/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
{{message}}
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Learn Python: Popular GitHub Repos (by ⭐️) With Flask
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Languages
17 |
27 |
28 |
29 |
30 |
Popular GitHub Repos (by ⭐️)
31 |
32 |
33 |
34 | {% if not results %}
35 | No Results.
36 | {% else %}
37 |
38 | Name
39 | Language
40 | Number Stars
41 |
42 | {% endif %}
43 |
44 | {% for result in results %}
45 |
46 | {{result.name}}
47 | {{result.language}}
48 | {{result.num_stars}}
49 |
50 | {% endfor %}
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/test.py:
--------------------------------------------------------------------------------
1 | import repos.api
2 | import repos.exceptions
3 |
4 | import unittest
5 |
6 | class TestCreateQuery(unittest.TestCase):
7 |
8 | def test_create_query(self):
9 | test_languages = ["Python", "Ruby", "Java"]
10 | test_min_stars = 10000
11 |
12 | expected = "language:Python language:Ruby language:Java stars:>10000"
13 | result = repos.api.create_query(test_languages, test_min_stars)
14 |
15 | self.assertEqual(result, expected, "Unexpected result from create_query")
16 |
17 |
18 | class TestGitHubApiException(unittest.TestCase):
19 |
20 | def test_exception_403(self):
21 | status_code = 403
22 | exception = repos.exceptions.GitHubApiException(status_code)
23 | self.assertTrue("Rate limit" in str(exception), "'Rate limit' not found")
24 |
25 | def test_exception_500(self):
26 | status_code = 500
27 | exception = repos.exceptions.GitHubApiException(status_code)
28 | self.assertTrue(str(status_code) in str(exception))
29 |
30 |
31 | if __name__ == "__main__":
32 | unittest.main()
33 |
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/pyworkshop/2_intermediate_python/chapter8/tests/__init__.py
--------------------------------------------------------------------------------
/pyworkshop/2_intermediate_python/chapter8/tests/tests.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/pyworkshop/2_intermediate_python/chapter8/tests/tests.py
--------------------------------------------------------------------------------
/website/.gitattributes:
--------------------------------------------------------------------------------
1 | *.png filter=lfs diff=lfs merge=lfs -text
2 | *.jpeg filter=lfs diff=lfs merge=lfs -text
3 | *.jpg filter=lfs diff=lfs merge=lfs -text
4 | *..eot filter=lfs diff=lfs merge=lfs -text
5 | *.svg filter=lfs diff=lfs merge=lfs -text
6 | *.eot filter=lfs diff=lfs merge=lfs -text
7 | *.ttf filter=lfs diff=lfs merge=lfs -text
8 | *.woff filter=lfs diff=lfs merge=lfs -text
9 | *.woff2 filter=lfs diff=lfs merge=lfs -text
10 | *.pdf filter=lfs diff=lfs merge=lfs -text
11 |
--------------------------------------------------------------------------------
/website/README.md:
--------------------------------------------------------------------------------
1 | Local setup instructions:
2 |
3 | 1. Install Hugo version v0.54.0 for the site to render properly
4 | 1. clone hugo learn theme from https://github.com/matcornic/hugo-theme-learn, update `themesdir` in config.toml
5 | 1. `cd python` then, `hugo server -D` to run local server
6 |
7 | Note: the file and folder names don't contribute to order, and may not always be accurate. Sorted by chapter and individual page weight.
8 |
9 | If you move things around or delete chapters, you may have to restart the server for the chapters to appear correctly.
10 |
11 | How to use the theme: https://learn.netlify.com/en/cont/
12 | More about theme shortcodes: https://learn.netlify.com/en/shortcodes/
13 |
14 | use `git lfs` for tracking binary types.
15 |
16 | ```bash
17 | $ git lfs track "*.psd"
18 | git add .gitattributes
19 | ```
20 |
21 | Currently tracked types:
22 | - .png
23 | - .jpg
24 | - .jpeg
25 | - .pdf
26 | - .mp4
27 | - .gif
--------------------------------------------------------------------------------
/website/archetypes/default.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "{{ replace .Name "-" " " | title }}"
3 | date: {{ .Date }}
4 | draft: true
5 | ---
6 |
7 |
--------------------------------------------------------------------------------
/website/config.toml:
--------------------------------------------------------------------------------
1 | baseURL = "/"
2 | languageCode = "en-US"
3 | defaultContentLanguage = "en"
4 |
5 | title = "Nina Zakharenko - Introduction and Intermediate Python"
6 | theme = "nnja-theme-learn"
7 | themesdir = "themes"
8 | metaDataFormat = "yaml"
9 | defaultContentLanguageInSubdir= true
10 | ignoreFiles = [ "\\.pyc$", "__pycache__"]
11 | publishDir = "docs"
12 | googleAnalytics = "UA-138644383-1"
13 |
14 | [params]
15 | # Change default color scheme with a variant one. Can be "red", "blue", "green".
16 | themeVariant = "blue"
17 | editURL = "https://github.com/nnja/python/edit/master/website/content/"
18 | defaultSocialImage = "images/twittercard.png"
19 | description = "Free Learn Python Course by Nina Zakharenko - An intensive two day introduction and intermediate course on Python. Video course published on Frontend Masters."
20 | author = "Nina Zakharenko"
21 | showVisitedLinks = true
22 | disableBreadcrumb = false
23 | disableNextPrev = false
24 | disableInlineCopyToClipBoard = true
25 | twitter = "nnja"
26 |
27 |
28 | # For search functionality
29 | [outputs]
30 | home = [ "HTML", "RSS", "JSON"]
31 |
32 | [Languages]
33 | [Languages.en]
34 | title = "Learn Python by Nina Zakharenko"
35 | weight = 1
36 | languageName = "English"
37 |
38 | [[Languages.en.menu.shortcuts]]
39 | name = " Github repo"
40 | identifier = "ds"
41 | url = "https://git.io/python3"
42 | weight = 10
43 |
44 | [[Languages.en.menu.shortcuts]]
45 | name = " Follow Nina on Twitter"
46 | url = "https://twitter.com/nnja"
47 | weight = 20
48 |
49 | [[Languages.en.menu.shortcuts]]
50 | name = " Credits"
51 | url = "/credits"
52 | weight = 30
--------------------------------------------------------------------------------
/website/content/01-introduction/00-who.md:
--------------------------------------------------------------------------------
1 | ---
2 | date: 2019-01-24T09:14:14-08:00
3 | title: About Your Instructor
4 | weight: 1
5 | draft: false
6 | ---
7 |
8 | # @nnja
9 |
10 | {{< figure src="/images/me.jpg" width="20%" title="Nina Zakharenko" >}}
11 |
12 |
13 | Hi, I'm Nina Zakharenko. I'm a Senior Cloud Developer Advocate at Microsoft, focusing on Python. Before Microsoft, I wrote code for other cool companies like Reddit, Meetup, and HBO. In my spare time I like drinking scotch and tinkering with wearable electronics. I enjoy hiking and snowboarding from my home base in Portland, Oregon. I change my hair color regularly.
14 |
15 |
16 | I've been involved in the Python community for approximately 6 years. During that time I've spoken at multiple Python conferences on a variety of topics, including PyCon US, PyParis, DjangoCon, and even PyCon Russia in Moscow.
17 |
18 | #### Stay in touch
19 | - @nnja
20 | - LinkedIn
21 | - GitHub where you can find the code for this site and my other projects
22 |
23 | I occasionally blog on Medium at @nnja . You can find out more about me on my homepage [nnja.io](https://nnja.io).
24 |
25 | #### Frontend Masters
26 |
27 | Check out my other [Frontend Masters courses](https://frontendmasters.com/teachers/nina-zakharenko/), such as [Git In-Depth](https://frontendmasters.com/courses/git-in-depth/).
28 |
29 | #### My Conference Talks
30 |
31 | You can watch a selection of my talks on YouTube
32 | such as:
33 |
34 | - [Elegant Solutions For Everyday Python Problems](https://www.youtube.com/watch?v=WiQqqB9MlkA) - PyCon 2018
35 | - [Memory Management in Python - The Basics](https://www.youtube.com/watch?v=F6u5rhUQ6dU) - PyCon 2016
36 | - [Code Review Skills for Pythonistas](https://www.youtube.com/watch?v=6L3ZVLtSeo8) - EuroPython 2018
37 | - [Five Things You Didn't Know Python Can Do](https://www.youtube.com/watch?v=WlGkBqBRsik) - All Things Open 2018
38 | - [Technical Debt - The Code Monster In Your Closet](https://www.youtube.com/watch?v=JKYktDRoRxw) - PyCon 2015
--------------------------------------------------------------------------------
/website/content/01-introduction/02-navigating-course.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Navigating The Course"
3 | date: 2019-02-04T00:13:49-08:00
4 | draft: false
5 | weight: 2
6 | ---
7 |
8 | The course content is free and open source, and hosted on GitHub. A link will be available *after the class* so that edits can be suggested via Pull Requests.
9 |
10 | ### Suggesting Changes to The Course Material
11 |
12 | If you notice a typo or any other issues with the material *after the class*, please open a pull request on GitHub by clicking the "Edit this page" button on the top right corner of every course page.
13 |
14 |
15 |
16 | 
17 |
18 | ### Clearing History of Read Pages
19 |
20 | Once a section is completed, a check mark will appear to the right of that section. To clear it, hit the "Clear History" button at the bottom of the table of contents on the left hand side.
21 |
22 | 
23 |
24 | ### Copying Code
25 |
26 | To copy code and commands, click on the clipboard icon (( ) on the top right of any code box.
27 |
28 | {{% notice tip %}}
29 | You can even copy code intended for the Python REPL. The prompt characters won't be copied over.
30 | {{% /notice %}}
31 |
32 | Try it now by coping the code below.
33 |
34 | ```python
35 | def greeting():
36 | print("Hello, World!")
37 | ```
38 |
39 | ### Searching
40 |
41 | The whole course is searchable via the search bar on the top left.
42 |
43 | 
44 |
45 | ### Navigation
46 |
47 | View the course contents in the side bar on the left.
48 |
49 | #### Arrows
50 |
51 | The course can be navigated sequentially to the page before or after via the left and right arrows on each page.
52 |
53 | 
54 |
55 | {{% notice tip %}}
56 | You can also use the left and right keyboard arrows to navigate between pages.
57 | {{% /notice %}}
58 |
59 | #### Breadcrumbs
60 |
61 | Use the breadcrumb links on the floating header of each page to jump between related sections.
62 |
63 | 
64 |
65 | #### Table of Contents
66 |
67 | Click on the "Table of Contents" Icon in the page header to jump between sections in the page.
68 |
69 | 
70 |
71 | ### Expanding Sections
72 |
73 | Sometimes additional instructions or information will be available via the expand section arrow. Keep an eye out for this icon:
74 |
75 | 
76 |
77 |
78 | {{% notice info %}}
79 | The course material is heavy in information and links. I suggest that you follow the links **after class** as a source of additional information, so that you don't get distracted from the important material.
80 | {{% /notice %}}
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/05-running-code.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Running Code"
3 | date: 2019-02-10T18:14:45-08:00
4 | draft: false
5 | weight: 5
6 | ---
7 |
8 | VS Code provides a built in terminal that allows us to easily run our programs. We'll mostly be working with Python program files at the end of Day 1, and for most of Day 2.
9 |
10 | ### Creating Python Files with the `*.py` extension
11 |
12 | You know a file is a Python program when it ends with a `.py` extension.
13 |
14 | #### Creating New Python Files
15 |
16 | To create a new file in VS Code, hit `Ctrl+N` on Windows and Linux, and `⌘N` (command + N) on Mac OS.
17 |
18 | This will open a new file. Next, save the file with a `.py` extension.
19 |
20 | {{% notice info %}}
21 | Create a new simple Python program in a file called `hello.py` in your `pyworkshop` directory with the following contents:
22 | {{% /notice %}}
23 |
24 | ```python
25 | # in file: hello.py
26 | greetings = ["Hello", "Bonjour", "Hola"]
27 |
28 | for greeting in greetings:
29 | print(f"{greeting}, World!")
30 | ```
31 |
32 | #### Opening The VS Code Terminal Window
33 |
34 | Next, you'll need to open your terminal if you don't have it open already. The quick keyboard shortcut to do that is Ctrl - `
35 |
36 | {{% notice note %}}
37 | If you already had your Python REPL open, you'll need to select a terminal with a shell in it (generally, the one labeled with `1:`).
38 | {{% /notice %}}
39 |
40 | 
41 | 
42 |
43 | #### Running The File
44 |
45 | Once you've opened your `hello.py` file and selected your new terminal window, open the VS Code command palette.
46 |
47 | {{% notice note %}}
48 | Open the command palette with `Ctrl+Shift+P` on Windows and Linux, and `⌘⇧P` (command + shift + P) on Mac OS.
49 | {{% /notice %}}
50 |
51 | Select Python: Run Python File in Terminal
52 |
53 | 
54 |
55 | You should see:
56 |
57 | ```bash
58 | Hello, World!
59 | Bonjour, World!
60 | Hola, World!
61 | ```
62 |
63 | How easy was that? 🎉
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Setting Up VS Code"
3 | date = 2019-01-25T15:05:31-06:00
4 | weight = 57
5 | chapter = true
6 | +++
7 |
8 | 
9 |
10 | # Visual Studio Code
11 |
12 | Visual Studio Code (or VS Code) is a free and open source graphical code editor. VS Code offers plenty of extensions to customize your experience. We'll be using the powerful Python extension to edit our code because it's jam-packed with helpful features.
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/command-palette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/command-palette.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/install-circuitpy.mp4:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/install-circuitpy.mp4
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/install-pylint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/install-pylint.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/interpreter.1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/interpreter.1.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/interpreter.2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/interpreter.2.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/open-folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/open-folder.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/popups copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/popups copy.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/popups.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/popups.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/repl-start.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/repl-start.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/repl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/repl.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/select-linter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/select-linter.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/select-pylint.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/select-pylint.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/selected-interpreter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/selected-interpreter.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/vs-code-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/vs-code-icon.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/vs-code-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/vs-code-logo.png
--------------------------------------------------------------------------------
/website/content/01-introduction/02-requirements/05-vs-code/images/welcome-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/02-requirements/05-vs-code/images/welcome-page.png
--------------------------------------------------------------------------------
/website/content/01-introduction/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Course Introduction
3 | weight: 1
4 | chapter: true
5 | ---
6 |
7 | # Learn Python
8 |
9 | Welcome to Introduction and Intermediate Python, recorded for Frontend Masters.
10 |
11 | Created by Nina Zakharenko. @nnja .
12 |
13 | Watch the accompanying screencast via subscription on [FrontendMasters.com](https://frontendmasters.com/teachers/nina-zakharenko/).
14 |
15 | {{< figure src="/images/fem.png" title="Watch the course" link="https://frontendmasters.com/courses/python/">}}
16 |
17 | Stay up to date with me on LinkedIn , or to contact me directly, please send me an email at learnpython@nnja.io .
18 |
19 | You can find the content and exercises on the Github repo .
20 |
21 |
22 | The course content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License .
23 |
24 | I'd like to encourage learning individuals to learn Python from the course material for free, but if you'd like to use the material for your own workshop or for commercial use, please consider supporting my work and [watch the screencast](https://frontendmasters.com/teachers/nina-zakharenko/) instead.
--------------------------------------------------------------------------------
/website/content/01-introduction/images/arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/arrows.png
--------------------------------------------------------------------------------
/website/content/01-introduction/images/clear_history.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/clear_history.png
--------------------------------------------------------------------------------
/website/content/01-introduction/images/copy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/copy.png
--------------------------------------------------------------------------------
/website/content/01-introduction/images/edit-page.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/edit-page.png
--------------------------------------------------------------------------------
/website/content/01-introduction/images/expand-section.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/expand-section.png
--------------------------------------------------------------------------------
/website/content/01-introduction/images/header.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/header.png
--------------------------------------------------------------------------------
/website/content/01-introduction/images/search.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/search.png
--------------------------------------------------------------------------------
/website/content/01-introduction/images/toc.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/01-introduction/images/toc.png
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/010-Best-Practices/02-brief-history.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "About Python 🐍"
3 | date: 2019-01-24T11:58:21-08:00
4 | draft: false
5 | weight: 2
6 | ---
7 |
8 | ### What is Python?
9 |
10 | Python is a programming language created by Guido Van Rossum in the late 1980s.
11 |
12 | You might be surprised to learn that Python is 30 years old!
13 |
14 | ### Where is it used?
15 |
16 | A common misconception is that Python is a scripting language. It's used at companies from Reddit, to Netflix, to Dropbox.
17 |
18 | ### What's all this about Python 2 vs Python 3
19 |
20 | This part is a bit of a stain on Python's history. Python 3 was released 2008, and its adoption was slow. First and foremost because it took popular packages a fair amount of time to port over their code.
21 |
22 | This debate is now over. Python 2 will reach end-of-life in 2020, meaning that important updates - including security updates - will stop being released. That's why this course focuses on *Python3 only*.
23 |
24 | ### Why Python?
25 |
26 | Python the language is [open source](https://github.com/python/cpython).
27 |
28 | Python has a wide variety of applications such as:
29 |
30 | - AI/ML
31 | - SciPi
32 | - NumPy
33 | - Pandas
34 | - PyTorch
35 | - Hardware & Micro-controllers
36 | - Raspberry Pi
37 | - MicroPython
38 | - CircuitPython
39 | - Web Development
40 | - Django
41 | - Flask
42 | - Scripting
43 | - DevOps
44 | Configuration scripts
45 |
46 | Python has an incredibly rich fully featured [standard library](https://docs.python.org/3/library/), as well as the [PyPI Package Index](https://pypi.org/) for 3rd party packages, which as of February 2019 contains 167,107 packages.
47 |
48 | Python is considered to be a "batteries included" language, because the standard library contains a majority of the libraries and packages you'll need in a standard application.
49 |
50 |
51 | ### Continuing In The Community
52 |
53 | The absolute best part about Python is the incredibly supportive community.
54 |
55 | The biggest yearly conference is [PyCon US](https://us.pycon.org) with approximately 4000 attendees.
56 |
57 | There are many local user groups worldwide, with many listed on [this wiki](https://wiki.python.org/moin/LocalUserGroups).
58 |
59 | There are many supportive groups for women and non-binary developers, such as [PyLadies](https://www.pyladies.com/) and [DjangoGirls](https://djangogirls.org/). These organizations have chapters in most major cities.
60 |
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/010-Best-Practices/03-conventions.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Conventions"
3 | date = 2019-02-10T21:46:57-08:00
4 | weight = 3
5 | draft = false
6 | +++
7 |
8 | ### PEP8
9 |
10 | [PEP8](https://pep8.org/) is a Python coding standard, that sets guidelines for how our Python code should look like.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/010-Best-Practices/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Why Choose Python"
3 | date = 2019-01-25T15:21:05-06:00
4 | weight = 10
5 | chapter = true
6 | draft = false
7 | pre = "1. "
8 | +++
9 |
10 | ### Chapter 1
11 |
12 | # Why Python?
13 |
14 | Let's talk about the anatomy of a Python program, what makes Python unique, and cover some best practices.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/020-basic-data-types/02-numbers.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Numbers"
3 | date: 2019-02-03T23:14:25-08:00
4 | draft: false
5 | weight: 2
6 | ---
7 |
8 | First, open up the REPL.
9 |
10 | {{% notice tip %}}
11 | Remember, you'll learn best if you type along with me.
12 | {{% /notice %}}
13 |
14 | There are three different types of numbers in Python: `int` for Integer, Float, and Complex.
15 |
16 | ```python
17 | # These are all integers
18 | x = 4
19 | y = -193394
20 | z = 0
21 | ```
22 |
23 | ```python
24 | # These are all floats
25 | x = 5.0
26 | y = -3983.2
27 | z = 0.
28 | ```
29 |
30 | ```python
31 | # This is a complex number
32 | x = 42j
33 | ```
34 |
35 | In Python, Integers and other simple data types are just objects under the hood. That means that you can create new ones by calling methods. You can provide either a number, or a string. This will come in handy later on in the course.
36 |
37 | ```python
38 | x = int(4)
39 | y = int('4')
40 | z = float(5.0)
41 | ```
42 |
43 | Python also provides a `decimal` library, which has certain benefits over the `float` datatype. For more information, refer to the [Python documentation](https://docs.python.org/3/library/decimal.html).
44 |
45 | ## Mathematical Operations
46 |
47 | Numbers can be added together. If you add a `float` and an `int`, the resulting type will be a `float`.
48 |
49 | If you divide two `int`s (integers), the result will be of type `float`.
50 |
51 | ## Boolean Types
52 |
53 | In Python, Booleans are of type `bool`. Surprisingly, the boolean types `True` and `False` are also numbers under the hood.
54 |
55 | * `True` is `1` under the hood.
56 | * `False` is `0` under the hood.
57 |
58 | That means you can do silly things, like add two Boolean numbers together, but I'll cover why this is a useful Python feature later in the course.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/020-basic-data-types/03-strings.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Strings"
3 | date: 2019-02-03T23:14:35-08:00
4 | draft: false
5 | weight: 3
6 | ---
7 |
8 | #### Representing Strings
9 |
10 | Strings in Python can be enclosed either with single quotes like `'hello'` or double quotes, like `"hello"`.
11 |
12 | Strings can also be **concatenated** (added together) using the `+` operator to combine an arbitrary number of Strings. For example:
13 |
14 | 1334
15 |
16 | ```python
17 | salutation = "Hello "
18 | name = "Nina"
19 | greeting = salutation + name
20 | # The value of greeting will be "Hello Nina"
21 | ```
22 |
23 | To use the same type of quote within a string, that quote needs to be **escaped** with a `\` - backwards slash.
24 |
25 | ```python
26 | greeting = 'Hello, it\'s Nina'
27 | ```
28 |
29 | Alternately, mixed quotes can be present in a Python string without escaping.
30 |
31 | ```python
32 | # Notice that the single quote ' is surrounded by
33 | # double quotes, ""
34 | greeting = "Hello, it's Nina"
35 | ```
36 |
37 | Long multi-line strings can be represented in between `"""` (triple quotes), but the whitespace will be part of the string.
38 |
39 | ```python
40 | long_greeting = """
41 | Greetings and salutations, dear Nina.
42 | I'm superfluous with my words,
43 | and require more space to say Hello!"
44 | """
45 | ```
46 |
47 | #### Printing Strings
48 |
49 | Strings can be printed out using the `print()` function in Python. While you're working the REPL, you'll see that variables are displayed for you. When you move on to writing standalone Python programs, that will no longer be the case.
50 |
51 | To use the `print()` function, call it with a regular or formatted string.
52 |
53 | ```python
54 | >>> print("Hello")
55 | Hello
56 | >>> name = "Nina"
57 | >>> print(name)
58 | Nina
59 | ```
60 |
61 | #### String Formatting
62 |
63 | There are several types of string formatting in Python.
64 |
65 | If you're using Python 3.7 and above (remember to check with `python --version` on the command line) you can use my favorite type of string formatting, and the one I'll be using for the course called f-strings.
66 |
67 | ```python
68 | >>> name = "Nina"
69 | >>> greeting = f"Hello, {name}"
70 |
71 | >>> print(greeting)
72 | Hello, Nina
73 | ```
74 |
75 | f-strings allow you to simply and easily reference variables in your code, and as a bonus, they're *much* faster.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/020-basic-data-types/05-common-string-and-number-errors.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Common Mistakes"
3 | date: 2019-02-10T18:33:43-08:00
4 | draft: false
5 | weight: 5
6 | ---
7 |
8 | There are a few common errors that you'll encounter when working with Strings and numbers. Remember, in Python program errors are called Exceptions. By going over what they are, you'll be able to recognize them immediately.
9 |
10 | ### Scenario 1: Mismatched string quotes
11 |
12 | {{% notice info %}}
13 | Mismatched string quotes will result in a `SyntaxError`
14 | {{% /notice %}}
15 |
16 | When we try to start a String with one type of quote, and end with another, we'll see a syntax error.
17 |
18 | For example, starting the string Hello with a double quote, and ending in a single quote, like this:
19 |
20 | #### Input: **"**Hello**'**
21 |
22 | For example, in the REPL:
23 |
24 | ```python
25 | >>> name = 'Hello"
26 | File "", line 1
27 | name = "Hello'
28 | ^
29 | SyntaxError: EOL while scanning string literal
30 | ```
31 |
32 | **Solution:** use matching quote types for defining your strings. Either single quotes `'Hello'` or double quotes `"Hello"`.
33 |
34 | ### Scenario 2: Trying to print a String and a number with concatenation using the "+" symbol.
35 |
36 | {{% notice info %}}
37 | Trying to add or concatenate a String and a number will result in a `TypeError`
38 | {{% /notice %}}
39 |
40 | If you add try to add (or concatenate) a String and a number, you'll get an error saying that adding the two types together isn't possible.
41 |
42 | #### Input: 3 + "Three"
43 |
44 | In the REPL:
45 | ```python
46 | >>> print(3 + " Three")
47 | Traceback (most recent call last):
48 | File "", line 1, in
49 | TypeError: unsupported operand type(s) for +: 'int' and 'str'
50 | ```
51 |
52 | **Solutions:**
53 |
54 | There are two possible solutions here, for two different scenarios.
55 |
56 | In the first scenario, you'd like to add a number to a string via concatenation. In order to do that, you must first convert the number to a string via the `str()` method.
57 |
58 | In the REPL:
59 | ```python
60 | >>> my_num = 3
61 | >>> print(str(my_num) + " Three")
62 | 3 Three
63 | ```
64 |
65 | In the second scenario, you'd like to a convert a number that's contained in a string (ex: `"3"`) into an Integer, so you can use it like any other number. In this case, you'd like to convert it to an Integer, with the `int()` method.
66 |
67 | In the REPL:
68 | ```python
69 | >>> str_num = "3"
70 | >>> print(int(str_num) + 5)
71 | 8
72 | ```
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/020-basic-data-types/10-exercise.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Practice"
3 | date: 2019-02-04T15:28:32-08:00
4 | draft: false
5 | weight: 10
6 | pre: "⭐️ "
7 | ---
8 |
9 | ## Basic Data Types, Strings and Numbers
10 |
11 | ### Types
12 |
13 | List the type of the following variables using the `type()` function.
14 |
15 | ```python
16 | >>> x = 42
17 | >>> y = 3 / 4
18 | >>> z = int('7')
19 | >>> a = float(5)
20 | >>> name = "Nina"
21 | ```
22 |
23 | ### Numbers
24 |
25 | Calculate the amount of rent you pay daily, by taking your monthly rent and diving it by 30.
26 |
27 | ```python
28 | >>> rent = 480
29 | >>> per_day = rent / 30
30 | >>> print(per_day)
31 | 16.0
32 | ```
33 |
34 | ### Strings
35 |
36 | Try printing some things to your REPL:
37 |
38 | ```python
39 | >>> print("Hello world")
40 | Hello world
41 | >>> name = "Nina"
42 | >>> print("My name is", name)
43 | My name is Nina
44 | ```
45 |
46 | There are three different ways to format strings in Python3. You may run into %-formatting and `str.format()` in older code. These are still common in Python but no longer recommended, due to readability concerns.
47 |
48 | ```python
49 | >>> name = "Nina"
50 | >>> print("Hello, my name is %s" % name)
51 | Hello, my name is Nina
52 | ```
53 |
54 | The current recommended way to format string is with f-Strings. f-Strings are much more readable and easier to maintain than the previous methods. With f-Strings, your string is prepended with the letter `f` and your variables or expressions to interpret are placed in `{brackets}`.
55 |
56 | ```python
57 | >>> name = "Nina"
58 | >>> print(f"Hello, my name is {name} and I pay ${rent / 30} in rent per day")
59 | Hello, my name is Nina and I pay $16.0 in rent per day
60 | ```
61 |
62 | ### Helper Functions
63 |
64 | Python has a few built-in functions to help you if you get stuck. `type()` tells you what an object's type is, for example a string (`str`) or integer (`int`). `dir()` returns a list of valid attributes for an object, so you can quickly see what variables an object has or what functions you can call on it. `help()` brings up helpful documentation on any object. You can also type `help()` on its own to bring an interactive help console.
65 |
66 | ```python
67 | >>> x = 42
68 | >>> y = 3 / 4
69 | >>> name = "Nina"
70 | >>> type(x)
71 |
72 | >>> type(y)
73 |
74 | >>> type(name)
75 |
76 | ```
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/020-basic-data-types/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Basic Data Types"
3 | date = 2019-01-25T15:02:51-06:00
4 | weight = 20
5 | chapter = true
6 | draft = false
7 | pre = "2. "
8 | +++
9 |
10 | ### Chapter 2
11 |
12 | # Basic Data Types
13 |
14 | Working with numbers, strings, and more.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/060-functions/40-scope.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Function Scope"
3 | date: 2019-02-10T18:30:11-08:00
4 | draft: false
5 | weight: 40
6 | ---
7 |
8 | ### Scope inside a function
9 |
10 | Inside of a function in Python, the **scope** changes.
11 |
12 | Think about it this way: scoping in Python happens with whitespace. When we delineate the code a function contains by indenting it under a function definition, it's scope **changes** to a new internal scope. It has access to the variables defined outside of it, but it can't change them.
13 |
14 | Once the function is done running, its scope goes away, as do its defined variables.
15 |
16 | Let's double check this in the REPL:
17 |
18 | ```python
19 | >>> def twitter_info():
20 | ... twitter_account = "nnja"
21 | ... print(f"Account inside function: {twitter_account}")
22 | ...
23 | >>> twitter_info()
24 | Account inside function: nnja
25 | >>> print(f"Account outside of function: {twitter_account}")
26 | Traceback (most recent call last):
27 | File "", line 1, in
28 | NameError: name 'twitter_account' is not defined
29 | ```
30 |
31 | We get a `NameError` when trying to access the `twitter_account` variable outside of the function. That's because it's out of scope, exactly like we expected it to be.
32 |
33 |
34 | ### Using variables defined outside of the function
35 |
36 | Generally, we want to be careful when using variables defined outside of our function.
37 |
38 | Note, that if we try to change the value of a variable defined outside of our function, we'll see the changes in the function, but not outside of it.
39 |
40 | You can't change variables defined outside of the function inside of the function. If you try to, your changes will only apply while the function is running. Once the function is done running, the value goes back to what it was before your function ran.
41 |
42 | A little confusing, but let's see it in action:
43 |
44 | ```python
45 | >>> name = "Nina"
46 | >>> print(f"Name outside of function: {name}")
47 | Name outside of function: Nina
48 | >>>
49 | >>> def try_change_name():
50 | ... name = "Max"
51 | ... print(f"Name inside of function: {name}")
52 | ...
53 | >>> try_change_name()
54 | Name inside of function: Max
55 | >>> print(f"Name outside of function: {name}")
56 | Name outside of function: Nina
57 | ```
58 |
59 | If we didn't know what to look for, the program might not behave how we'd expect it to. A good rule of thumb is to name our variables clearly, and minimize how many variables we declare outside of functions and classes, which you'll learn about in day two.
60 |
61 |
62 | {{% notice tip %}}
63 | An appropriate use is when using a constant, a variable defined in all caps, with the words separated by underscores. A constant is a value that we expect to use several times within our program, but we never expect to change it programmatically.
64 | {{% /notice %}}
65 |
66 | For example:
67 |
68 | ```python
69 | >>> ROOT_API_URL = "https://api.github.com"
70 | >>> def api_search_repos_url():
71 | ... return f"{ROOT_API_URL}/search/repositories"
72 | ...
73 | >>> api_search_repos_url()
74 | 'https://api.github.com/search/repositories'
75 | >>>
76 | ```
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/060-functions/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Functions"
3 | date = 2019-01-25T15:03:48-06:00
4 | weight = 60
5 | chapter = true
6 | draft = false
7 | pre = "3. "
8 | +++
9 |
10 | ### Chapter 3
11 |
12 | # Functions
13 |
14 | Functions help us organize our code in a way that's reusable, and accept arguments and defaults where needed.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/080-advanced-datatypes/65-mutability.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Mutability Cheat Sheet"
3 | date: 2019-03-03T13:06:52-08:00
4 | draft: false
5 | weight: 65
6 | ---
7 |
8 | ### Mutability
9 |
10 | Mutability, simply put: the contents of a mutable object can be changed, while the contents of an immutable object cannot be.
11 |
12 | ### Simple Types
13 |
14 | All of the simple data types we covered first are **immutable**
15 |
16 | | type | use | mutable? |
17 | |--------------------------- |------------------------- |---------- |
18 | | `int`, `float`, `decimal` | store numbers | **no** |
19 | | `str` | store strings | **no** |
20 | | `bool` | store `True` or `False` | **no** |
21 |
22 | ### Container Types
23 |
24 | For the mutability of the container types we covered in this chapter, check this helpful list:
25 |
26 | | container type | use | mutable? |
27 | |---------------- |--------------------------------------------------------------------------------------------------------- |---------- |
28 | | `list` | ordered group of items, accessible by position | **yes** |
29 | | `set` | mutable unordered group consisting only of immutable items. useful for set operations (membership, intersection, difference, etc) | **yes** |
30 | | `tuple` | contain ordered groups of items in an **immutable** collection | **no** |
31 | | `dict` | contains key value pairs | **yes** |
32 |
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/080-advanced-datatypes/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Advanced Container Types"
3 | date = 2019-01-25T15:04:34-06:00
4 | weight = 80
5 | chapter = true
6 | draft = false
7 | pre = "4. "
8 | +++
9 |
10 | ### Chapter 4
11 |
12 | # Advanced Data Types - Containers and sequences
13 |
14 | Now that we've got the basics of strings and numbers down, let's talk about the advanced data types - `list`, `tuple`, `dict` and `set`. These are container objects that let us organize other types of objects into one data structure.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/090-boolean-logic/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Boolean Logic"
3 | date = 2019-01-25T15:04:16-06:00
4 | weight = 90
5 | chapter = true
6 | draft = false
7 | pre = "5. "
8 | +++
9 |
10 | ### Chapter 5
11 |
12 | # Boolean Logic
13 |
14 | Boolean Logic allows you to test your assumptions.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/110-control-statements-looping/30-while-loops.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "while loops"
3 | date: 2019-02-10T18:22:01-08:00
4 | draft: false
5 | weight: 30
6 | ---
7 |
8 | `while` loops are a special type of loop in Python. Instead of running just once when a condition is met, like an `if` statement, they run **forever** until a condition is *no longer* met.
9 |
10 | `while` loops usually need to be accompanied by an always changing sentinel value.
11 |
12 | ```python
13 | >>> counter = 0
14 | >>> max = 4
15 | >>>
16 | >>> while counter < max:
17 | ... print(f"The count is: {counter}")
18 | ... counter = counter + 1
19 | ...
20 | The count is: 0
21 | The count is: 1
22 | The count is: 2
23 | The count is: 3
24 | ```
25 |
26 | {{% notice warning %}}
27 | Our loop will run forever if we forget to *update* the sentinel value. **Press Ctrl-C to exit the infinite loop.**
28 | {{% /notice %}}
29 |
30 |
31 | ```python
32 | # Warning: don't copy and paste this example.
33 |
34 | >>> counter = 0
35 | >>> max = 4
36 |
37 | >>> while counter < max:
38 | ... print(f"The count is: {counter}")
39 | ...
40 | # What happens if we don't update counter?
41 | The count is: 0
42 | The count is: 0
43 | The count is: 0
44 | The count is: 0
45 | # An infinite loop repeated until we hit Ctrl-C
46 | The count ^CTraceback (most recent call last):
47 | File "", line 2, in
48 | KeyboardInterrupt
49 | ```
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/110-control-statements-looping/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Loops and Control Statements"
3 | date = 2019-01-25T15:16:00-06:00
4 | weight = 110
5 | chapter = true
6 | draft = false
7 | pre = "6. "
8 | +++
9 |
10 | ### Chapter 6
11 |
12 | # Loops and Control Statements
13 |
14 | Loops and control statements allow us to control the logical flow of our program.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/110-control-statements-looping/code/names.py:
--------------------------------------------------------------------------------
1 | names = ["Jimmy", "Rose", "Max", "Nina", "Phillip"]
2 |
3 | for name in names:
4 | if len(name) != 4:
5 | continue
6 |
7 | print(f"Hello, {name}")
8 |
9 | if name == "Nina":
10 | break
11 |
12 | print("Done!")
13 |
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/110-control-statements-looping/images/break-continue.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/110-control-statements-looping/images/break-continue.png
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/65-libraries.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Working with Libraries"
3 | date = 2019-01-25T15:06:06-06:00
4 | weight = 65
5 | draft = false
6 | +++
7 |
8 | Working with external libraries in Python makes use of the `import` keyword. While this can go anywhere in your file, it's almost always best to import libraries at the top of each file where they're used. For example, in the last section, we were able to call upon the built-in `json` library by calling `import json` at the top of our code.
9 |
10 | Importing modules with the `import` keyword is usually the best method, because it preserves the module's namespace. However, you can also use the `from import ` syntax to import a specific object (function, variable, subclass, etc.) from a module into your program's namespace.
11 |
12 | For example, if we wanted a random integer between 0 and 100, we could use `random.randint()`:
13 |
14 | ```python
15 | >>> import random
16 | >>> random.randint(0, 100)
17 | 42
18 | ```
19 |
20 | Notice that the namespace is preserved (we needed to call `random.randint()`). If we use `from` instead:
21 |
22 | ```python
23 | >>> from random import randint
24 | >>> randint(0, 100)
25 | 64
26 | ```
27 |
28 |
29 | ### Installing the requests library with `pip`
30 |
31 | For the next chapter, we'll be using an excellent 3rd part library called `requests` to make light work of retrieving data from web APIs. To install the `requests` library, run this on your command line:
32 |
33 | ```bash
34 | (env) $ python -m pip install requests
35 | ```
36 |
37 | This runs the `pip` module and asks it to find the `requests` library on PyPI.org (the Python Package Index) and install it in your local system, so that it becomes available for you to import. We'll dive a little more into this later.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Working With Python Programs"
3 | date = 2019-01-25T15:05:49-06:00
4 | weight = 175
5 | chapter = true
6 | draft = false
7 | pre = "7. "
8 | +++
9 |
10 | ### Chapter 7
11 |
12 | # Working With Python Programs
13 |
14 | The REPL is an incredibly useful tool to quickly learn new Python concepts and test your assumptions. Unfortunately, it's not a great way to save or share our code. Let's learn how to save our Python code into project files, so we can run it again and again.
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/exceptions.py:
--------------------------------------------------------------------------------
1 | try:
2 | int("a")
3 | except ValueError as error:
4 | print(f"Something went wrong. Message: {error}")
5 |
6 | print("Reached end of the program.")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/exceptions_one.py:
--------------------------------------------------------------------------------
1 | # this will throw an exception!
2 | int("a")
3 |
4 | print("Reached end of the program.")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/exceptions_two.py:
--------------------------------------------------------------------------------
1 | try:
2 | int("a")
3 | except ValueError:
4 | print("Oops, couldn't convert that value into an int!")
5 |
6 | print("Reached end of the program.")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/formatting_example.py:
--------------------------------------------------------------------------------
1 | # Use \n to add a new line, before, in the middle of, or after a string.
2 | print("\nExtra New Line Before")
3 | print("One Print\nTwo New Lines!")
4 | print("Extra New Line After\n")
5 |
6 | # Use \t to add a tab.
7 | print("\t Here's some tabbed output.")
8 |
9 | # Or, combine both!
10 | print("\nOne Print\n\tOne Tab")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/hello.py:
--------------------------------------------------------------------------------
1 | greetings = ["Hello", "Bonjour", "Hola"]
2 |
3 | for greeting in greetings:
4 | print(f"{greeting}, World!")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/mystery.py:
--------------------------------------------------------------------------------
1 | def mystery():
2 | num = 10 * 3
3 |
4 | if num == 10:
5 | print("Num was equal to 10")
6 | num = num * 10
7 | if num == 20:
8 | print("Num was equal to 20")
9 | num = num * 20
10 | if num == 30:
11 | print("Num was equal to 30")
12 | num = num * 30
13 |
14 | print(f"Value of returned num is: {num}")
15 | return num
16 |
17 | mystery()
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/name.py:
--------------------------------------------------------------------------------
1 | name = "Nina"
2 | name
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/name_lib.py:
--------------------------------------------------------------------------------
1 | def name_length(name):
2 | return len(name)
3 |
4 | def upper_case_name(name):
5 | return name.upper()
6 |
7 | def lower_case_name(name):
8 | return name.lower()
9 |
10 | name = "Nina"
11 | length = name_length(name)
12 | upper_case = upper_case_name(name)
13 |
14 | print(f"The length is {length} and the uppercase version is: {upper_case}")
15 | # print(f"The value of __name__ is: {__name__}")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/name_lib_main.py:
--------------------------------------------------------------------------------
1 | def name_length(name):
2 | return len(name)
3 |
4 | def upper_case_name(name):
5 | return name.upper()
6 |
7 | def lower_case_name(name):
8 | return name.lower()
9 |
10 | if __name__ == "__main__":
11 | name = "Nina"
12 | length = name_length(name)
13 | upper_case = upper_case_name(name)
14 |
15 | print(f"The length is {length} and the uppercase version is: {upper_case}")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/other_program.py:
--------------------------------------------------------------------------------
1 | import name_lib
2 |
3 | my_name = "Fred"
4 |
5 | my_length = name_lib.name_length(my_name)
6 | my_lower_case = name_lib.lower_case_name(my_name)
7 |
8 | print(f"In my code, my length is {my_length} and my lower case name is: {my_lower_case}")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/other_program_main.py:
--------------------------------------------------------------------------------
1 | import name_lib_main
2 |
3 | my_name = "Fred"
4 |
5 | my_length = name_lib_main.name_length(my_name)
6 | my_lower_case = name_lib_main.lower_case_name(my_name)
7 |
8 | print(f"In my code, my length is {my_length} and my lower case name is: {my_lower_case}")
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/code/print_name.py:
--------------------------------------------------------------------------------
1 | name = "Nina"
2 | print(name)
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/images/.gitattributes:
--------------------------------------------------------------------------------
1 | *.png filter=lfs diff=lfs merge=lfs -text
2 |
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/images/terminal-drop-down-select.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/175-running-code/images/terminal-drop-down-select.png
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/images/terminal-drop-down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/175-running-code/images/terminal-drop-down.png
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/175-running-code/images/vs-code-run-file-command-palette.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/175-running-code/images/vs-code-run-file-command-palette.png
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/00-what-is-an-API.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "What Is an API?"
3 | date: 2019-03-16T21:38:31-07:00
4 | draft: false
5 | weight: 1
6 | ---
7 |
8 | Per the dictionary, an API is:
9 |
10 | > a set of functions and procedures allowing the creation of applications that access the features or data of an operating system, application, or other service.
11 |
12 | An API is a standardized way of accessing information across the web, between clients and servers. These days most APIs are *RESTful*. That means they follow a common set of paradigms and practices.
13 |
14 | There are many types of APIs, but these days they're commonly known to refer to *web* APIs.
15 |
16 | #### Authentication
17 |
18 | Some, but not all APIs require you to authenticate. Methods of authentication are out of the scope of this class, but you'll be happy to know that there are plenty of free APIs available that require no authentication at all.
19 |
20 | #### Rate Limiting
21 |
22 | Some APIs allow unauthenticated requests, but they're usually *rate limited*. Rate limiting means prevent the same client (usually by IP address) from making too many requests at once and overloading the server. *The GitHub API allows 50 unauthenticated requests per hour per IP, or 10 unauthenticated requests to their Search API.*
23 |
24 | Note: After the class, you can find a detailed list of APIs in this [public-apis repo](https://github.com/toddmotto/public-apis).
25 |
26 | #### Free APIs
27 |
28 | {{% notice note %}}
29 | Free APIs are... free. That means that they may go down if their owner decides to drop their upkeep. If the API used in these examples doesn't work in the future, try a different one listed in the `public-apis` repo linked to above.
30 | {{% /notice %}}
31 |
32 |
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "APIs"
3 | date = 2019-01-25T15:06:53-06:00
4 | weight = 190
5 | chapter = true
6 | draft = false
7 | pre = "8. "
8 | +++
9 |
10 | ### Chapter 8
11 |
12 | # Working with APIs
13 |
14 | How do we interact with APIs from Python?
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/images/200.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/190-APIs/images/200.jpeg
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/images/301.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/190-APIs/images/301.jpeg
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/images/404.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/190-APIs/images/404.jpeg
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/images/500.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/190-APIs/images/500.jpeg
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/images/Htcpcp_teapot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/190-APIs/images/Htcpcp_teapot.jpg
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/190-APIs/images/request-response.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/02-introduction-to-python/190-APIs/images/request-response.jpeg
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/200-conclusion/00-wrapping-up.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Wrapping Up"
3 | date: 2019-02-10T18:39:32-08:00
4 | draft: false
5 | ---
6 |
7 | Today you've gotten a whirlwind tour of the Python programming language.
8 |
9 | During Day 2, we're going to put our knowledge to work writing real programs.
10 |
11 | ## Source Control
12 |
13 | I highly recommend that you use source control while working on your Python projects. GitHub is a popular and free option.
14 |
15 | Source control lets you track changes to your project. You can use that to your advantage to commit early and often and track changes to your project.
16 |
17 | If you're not familiar with how to use git or GitHub, you can watch my [Git In-depth Frontend Masters class](https://frontendmasters.com/courses/git-in-depth/). For Python projects, make sure that you use the correct `.gitignore` file. GitHub provides a [free template that you can use](https://github.com/github/gitignore/blob/master/Python.gitignore).
18 |
--------------------------------------------------------------------------------
/website/content/02-introduction-to-python/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | pre: "Day 1. "
3 | title: "Intro to Python"
4 | date: 2019-01-24T08:21:04-08:00
5 | draft: false
6 | chapter: true
7 | weight: 2
8 | ---
9 |
10 | ### Day 1
11 |
12 | # An Introduction to Python
13 |
14 | Let's talk about the anatomy of a Python program, along with Python best practices like naming and commenting.
15 |
16 | Today you'll be learning all the foundational basics of Python. How to work with different data types, the Python control structures, best practices, and lastly an exercise in interacting with APIs.
17 |
18 | # Day 1 Overview
19 |
20 | By coding along with me in this workshop, you'll:
21 |
22 | * You’ll learn about the origins of Python, and how it can help you solve complex problems quickly.
23 | * Learn about the different data types Python has to offer, including tips on when and how to use each one.
24 | * Understand the control flow of Python programs - loops, boolean statements, if statements, and return statements.
25 | * Make your code more concise by writing reusable functions.
26 | * Learn to use Python packages from the standard library, as well as how to find and install external libraries.
27 | * Learn how to work with files on your filesystem by reading and writing to them.
28 | * Write programs that interact with APIs by sending requests and receiving responses.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/00-final-project-preview.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Final Project Preview"
3 | date = 2019-03-03T11:56:24-08:00
4 | weight = 1
5 | draft = false
6 | +++
7 |
8 | ### Final Project Preview
9 |
10 | Our final project on Day 2 will involve creating a simple Flask web application from our Day 1 final exercise.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/10-introduction/00-getting-ready.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Getting Ready"
3 | date = 2019-03-03T11:56:24-08:00
4 | weight = 1
5 | draft = false
6 | +++
7 |
8 | ### Get Ready For Day 2 - Navigate To Your Project
9 |
10 | Building on the project structure from Day 1, enter your `~/pyworkshop` directory, and start your already existing virtual environment.
11 |
12 | Windows:
13 |
14 | ```powershell
15 | > cd $home
16 | > cd pyworkshop
17 | > env\scripts\activate
18 | ```
19 |
20 | Mac:
21 |
22 | ```bash
23 | $ cd ~/pyworkshop
24 | $ source env/bin/activate
25 | ```
26 |
27 | ### Open VS Code
28 |
29 | If VS Code isn't already open, type the following in the same PowerShell or Terminal window where you activated your virtual environment.
30 |
31 | ```text
32 | $ code .
33 | ```
34 |
35 | ### Start The REPL
36 |
37 | Open the Command Palette in VS Code, and type: "Python: Start REPL"
38 |
39 | {{% notice tip %}}
40 | Remember, open the VS Code command palette (cmd + shift + P on Mac, ctrl + shift + P on Windows) and
41 | {{% /notice %}}
42 |
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/10-introduction/00-python-philosophy.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Python Philosophy"
3 | date = 2019-03-03T11:56:24-08:00
4 | weight = 3
5 | draft = false
6 | +++
7 |
8 | The Zen of Python is a collection of 19 software principles written in a poem that influences the design of Python Programming Language. It was published on the Python mailing list in June 1999 by Tim Peters. [*](https://en.wikipedia.org/wiki/Zen_of_Python)
9 |
10 | ### Zen of Python in The Python Interpreter
11 |
12 | The Zen of Python is included as an easter egg in the Python REPL. You can read it by typing `import this` in our REPL, to learn a little more about the principles and philosophy behind Python.
13 |
14 | ```python
15 | >>> import this
16 | The Zen of Python, by Tim Peters
17 |
18 | Beautiful is better than ugly.
19 | Explicit is better than implicit.
20 | Simple is better than complex.
21 | Complex is better than complicated.
22 | Flat is better than nested.
23 | Sparse is better than dense.
24 | Readability counts.
25 | ```
26 |
27 | #### Simple is Better Than Complex
28 |
29 | Generally, Python programmers prefer to be explicit and write *simple*, *understandable*, and *maintainable* code instead of ego flexing and writing unnecessarily complex code.
30 |
31 | #### Readability Counts
32 |
33 | Make your code easy to read. Avoid single character variable names. Call your functions with named parameters where applicable. Use good variable names.
34 |
35 | #### More Easter Eggs
36 |
37 | {{% notice note %}}
38 | To see another Python easter egg, type the following into your REPL: `from __future__ import braces`
39 | {{% /notice %}}
40 |
41 | {{%expand "You'll see the following: 🤣" %}}
42 | ```python
43 | >>> from __future__ import braces
44 | File "", line 1
45 | SyntaxError: not a chance
46 | ```
47 | {{% /expand%}}
48 |
49 | {{% notice note %}}
50 | My favorite Easter Egg? Type `import antigravity` into the REPL.
51 | {{% /notice %}}
52 |
53 | 
54 |
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/10-introduction/15-converting-between-types/04-string-operations.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "String Operations"
3 | date: 2019-02-10T18:30:43-08:00
4 | draft: false
5 | weight: 4
6 | ---
7 |
8 | ### Split and Join
9 |
10 | Strings have two functions for splitting and joining - `split()` and `join()`. Calling `split()` on a string will split the string into a list, creating a new element for every instance of the character(s) you pass in. `join()` accepts a list of strings, and uses the string you call it on to join the list together into one string. For example:
11 |
12 | ```python
13 | >>> my_data = "this,is,comma,separated,data"
14 | >>> my_data = my_data.split(",")
15 | >>> print(my_data)
16 | ['this', 'is', 'comma', 'separated', 'data']
17 |
18 | >>> ":".join(my_data)
19 | 'this:is:comma:separated:data'
20 |
21 | >>> ", ".join(my_data)
22 | 'this, is, comma, separated, data'
23 | ```
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/10-introduction/15-converting-between-types/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Converting Between Types"
3 | date = 2019-01-25T15:05:14-06:00
4 | weight = 4
5 | draft = false
6 | +++
7 |
8 | Easily converting between different datatypes is one of Python's superpowers! Let's see how...
9 |
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/10-introduction/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "More Python Ideas"
3 | date = 2019-01-25T15:21:05-06:00
4 | weight = 10
5 | chapter = true
6 | draft = false
7 | pre = "1. "
8 | +++
9 |
10 | ### Chapter 1
11 |
12 | # More Python Ideas
13 |
14 | Let's learn a little more about Python, and talk about more best practices, to help you get an idea of what "good" Python code should look like.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/10-introduction/images/python.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/03-intermediate-python/10-introduction/images/python.png
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/20-advanced-looping/50-slicing.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Slicing"
3 | date: 2019-03-10T19:13:03-07:00
4 | draft: false
5 | weight: 5
6 | ---
7 |
8 | Slicing is a easy way to create sub-lists from larger lists. If you remember back to our exercise on data types, we can use a slice to obtain a subset of items from a `list`. Remember that a string is just a list of characters. For example:
9 |
10 | ```python
11 | >>> my_string = "Hello, world!"
12 | >>> my_string[7:12] # from 7 to 12
13 | 'world'
14 | ```
15 |
16 | ### Lopsided Slicing
17 |
18 | You can also leave out one of the numbers in the slice. Leaving out the first number is equivalent to using a zero - you can think of this as "from the beginning." Leaving out the last number is equivalent to using the length of the list you're slicing - you can think of this as "until the end." For example:
19 |
20 | ```python
21 | >>> my_string = "Hello, world!"
22 | >>> my_string[:5] # from zero to 5
23 | 'Hello'
24 | >>> my_string[7:] # from 7 to the end
25 | 'world!'
26 | ```
27 |
28 | You can also leave out both sides of the slice! You can think of this as "from the beginning, until the end." Why? This is an easy way to copy a list!
29 |
30 | ```python
31 | >>> my_new_string = my_string[:]
32 | >>> my_new_string
33 | 'Hello, world!'
34 | ```
35 |
36 | ### Negative Indexing
37 |
38 | You aren't limited to positive numbers for your slicing, either. A negative number on the left side will wrap around to the other side of your list. A negative number on the right side is equivalent to the length of the list minus your number. For example:
39 |
40 | ```python
41 | >>> my_string = "Hello, world!"
42 | >>> my_string[-6:] # from the end - 6 to the end
43 | 'world!'
44 | >>> my_string[-10:-4] # from the end - 10 to the end - 4
45 | 'lo, wo'
46 | ```
47 |
48 | You can also use just a single negative number to get an item counting *backwards* from the end of a `list`. For example, to get the last item from a list:
49 |
50 | ```python
51 | >>> my_list = [1, 3, 3, 7]
52 | >>> my_list[-1]
53 | 7
54 | ```
55 |
56 | ### Stride or Step
57 |
58 | Python slices also have a *third*, optional argument, called "step" or "stride", separated by a second colon. This lets you skip elements of a list or even reverse them. For example:
59 |
60 | ```python
61 | >>> my_list = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
62 | >>> my_list[::2] # move forward by 2, or skip every other index
63 | [0, 2, 4, 6, 8]
64 | >>> my_list[::-1] # move backward by 1, and easy way to reverse a list
65 | [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
66 | >>> my_list[1:7:2] # get every other index between 1 and 7
67 | [1, 3, 5]
68 | ```
69 |
70 | {{% notice note %}}
71 | You can use a slice to get a subset of items from any data type that maintains an order, such as a `list` or `tuple`, but not from any non-ordered data types, such as `dict` or `set`.
72 | {{% /notice %}}
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/20-advanced-looping/70-zip.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "The zip function"
3 | date: 2019-03-03T18:03:03-08:00
4 | draft: false
5 | weight: 7
6 | ---
7 |
8 | It's often necessary to iterate over multiple lists simultaneously. Suppose we're keeping score of a game and we have two lists, one for names and one for scores:
9 |
10 | ```python
11 | >>> names = ["Bob", "Alice", "Eve"]
12 | >>> scores = [42, 97, 68]
13 | ```
14 |
15 | The `zip` function takes any number of iterable arguments and steps through
16 | all of them at the same time until the end of the *shortest* iterable has been reached:
17 |
18 | ```python
19 | >>> for name, score in zip(names, scores):
20 | >>> print(f"{name} had a score of {score}.")
21 | ...
22 | Bob had a score of 42.
23 | Alice had a score of 97.
24 | Eve had a score of 68.
25 | ```
26 |
27 | What will the above loop print after removing the last element from `scores`?
28 |
29 | ```python
30 | >>> scores.pop(-1)
31 | 68
32 | >>> for name, score in zip(names, scores):
33 | >>> print(f"{name} had a score of {score}.")
34 | ...
35 | Bob had a score of 42.
36 | Alice had a score of 97.
37 | ```
38 |
39 | The loop terminates even though there are more values in `names`. Here, Eve isn't included because `scores` only has two elements.
40 |
41 | We can also use `zip()` to quickly and easily create a `dict` from two lists. For example:
42 |
43 | ```python
44 | >>> scores = [42, 97, 68]
45 | >>> score_dict = dict(zip(names, scores))
46 | >>> print(score_dict)
47 | {'Bob': 42, 'Alice': 97, 'Eve': 68}
48 | ```
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/20-advanced-looping/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Advanced Looping"
3 | date = 2019-03-03T11:57:04-08:00
4 | weight = 20
5 | draft = false
6 | chapter = true
7 | pre = "2. "
8 | +++
9 |
10 | ### Chapter 2
11 |
12 | # Advanced Looping with List Comprehensions
13 |
14 | Learn about advanced looping with list comprehensions, and other types of comprehensions.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/30-oop-classes-inheritance/10-concept.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Concept"
3 | date: 2019-03-10T19:29:28-07:00
4 | draft: false
5 | weight: 1
6 | ---
7 |
8 | Object-oriented Programming (OOP) is a language model (or *paradigm*) in which properties or behaviors are organized into "objects". Some languages encourage a more procedural style, like if you were writing a recipe - some popular examples are COBOL and BASIC. Languages that adopt an Object-oriented style organize things into objects, and provide methods for objects to communicate with one another.
9 |
10 | ### What is an object?
11 |
12 | An object can be a function, a variable, a property, a class... everything in Python is an object. You can think of an object as a generic container - a `list` object might contain a sequence of `int` objects, along with some function objects. The `int` objects contain integer numbers. The function objects contain code that can be executed on the `list` object or maybe on the items in the `list`.
13 |
14 |
15 | ### Python and OOP
16 |
17 | Python buys heavily into the OOP model - you'll find that everything in Python is an object of some kind, and almost everything has attributes and methods.
18 |
19 | This doesn't mean you *have* to use OOP in your programs - Python works perfectly well as a procedural or "script" language, where one command is executed after another, like a recipe. But getting familiar with OOP will not only help you read other Python code, but it will help you learn to encapsulate your code into objects for better organization and readability, as well as increase efficiency by making your code easily reusable. Objects are center-stage in Python, representing not only the data, but the overall structure of your programs as well.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/30-oop-classes-inheritance/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Object Oriented Programming"
3 | date = 2019-03-03T11:58:39-08:00
4 | weight = 30
5 | chapter = true
6 | draft = false
7 | pre = "3. "
8 | +++
9 |
10 | ### Chapter 3
11 |
12 | # Classes, Objects, Object Oriented programming
13 |
14 | Object oriented programming allows us to represent our code in a different way, organized into `class`es
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/40-exceptions/30-try-except-else-finally.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Try Except"
3 | date: 2019-03-10T19:15:54-07:00
4 | draft: false
5 | weight: 3
6 | ---
7 |
8 | Many languages have the concept of the "Try-Catch" block. Python uses four keywords: `try`, `except`, `else`, and `finally`. Code that can possibly throw an exception goes in the `try` block. `except` gets the code that runs if an exception is raised. `else` is an optional block that runs if no exception was raised in the `try` block, and `finally` is an optional block of code that will run last, regardless of if an exception was raised. We'll focus on `try` and `except` for this chapter.
9 |
10 | A basic example looks like this:
11 |
12 | ```python
13 | >>> try:
14 | ... x = int(input("Enter a number: "))
15 | ... except ValueError:
16 | ... print("That number was invalid")
17 | ```
18 |
19 | First, the `try` clause is executed. If no exception occurs, the `except` clause is skipped and execution of the `try` statement is finished. If an exception occurs in the `try` clause, the rest of the clause is skipped. If the exception's type matches the exception named after the `except` keyword, then the `except` clause is executed. If the exception doesn't match, then the exception is *unhandled* and execution stops.
20 |
21 |
22 | ### The `except` Clause
23 |
24 | An `except` clause may have multiple exceptions, given as a parenthesized tuple:
25 |
26 | ```python
27 | try:
28 | # Code to try
29 |
30 | except (RuntimeError, TypeError, NameError):
31 | # Code to run if one of these exceptions is hit
32 | ```
33 |
34 | A `try` statement can also have more than one `except` clause:
35 |
36 | ```python
37 | try:
38 | # Code to try
39 |
40 | except RuntimeError:
41 | # Code to run if there's a RuntimeError
42 |
43 | except TypeError:
44 | # Code to run if there's a TypeError
45 |
46 | except NameError:
47 | # Code to run if there's a NameError
48 | ```
49 |
50 | ### Finally
51 |
52 | Finally, we have `finally`. `finally` is an optional block that runs after `try`, `except`, and `else`, regardless of if an exception is thrown or not. This is good for doing any cleanup that you want to happen, whether or not an exception is thrown.
53 |
54 | ```python
55 | >>> try:
56 | ... raise KeyboardInterrupt
57 | ... finally:
58 | ... print("Goodbye!")
59 | ...
60 | Goodbye!
61 | Traceback (most recent call last):
62 | File "", line 2, in
63 | KeyboardInterrupt
64 | ```
65 |
66 | As you can see, our Goodbye! gets printed just before the unhandled `KeyboardInterrupt` gets propagated up and triggers the traceback.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/40-exceptions/50-exception-hierarchy.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Exception Hierarchy"
3 | date: 2019-03-10T19:15:44-07:00
4 | draft: true
5 | weight: 5
6 | ---
7 |
8 | Python has many useful built-in exceptions that you'll probably encounter in your travels. Some of the more common ones that you'll run into are listed in the [All About Exceptions](../10-all-about-exceptions) section. You can find a more detailed list of built-in exceptions in the [Python documentation](https://docs.python.org/3/library/exceptions.html).
9 |
10 | An important thing to know is that exceptions, like everything else in Python, are just objects. They follow an inheritance hierarchy, just like classes do. For example, the `ZeroDivisionError` is a subclass of `ArithmeticError`, which is a subclass of `Exception`, itself a subclass of `BaseException`.
11 |
12 | ```python
13 | >>> issubclass(ZeroDivisionError, ArithmeticError)
14 | True
15 | >>> issubclass(ArithmeticError, Exception)
16 | True
17 | >>> issubclass(Exception, BaseException)
18 | True
19 |
20 | # Thus,
21 | >>> issubclass(ZeroDivisionError, BaseException)
22 | True
23 | ```
24 |
25 | So, if you wanted to catch a divide-by-zero error, you could use `except ZeroDivisionError`. But you could also use `except ArithmeticError`, which would catch not only `ZeroDivisionEror`, but also `OverflowError` and `FloatingPointError`. You could use `except Exception`, but this is not a good idea, as it will catch almost *every* type of error, even ones you weren't expecting. We'll discuss this a bit later.
26 |
27 | A full chart of the hierarchy for built-in exceptions can be found at the bottom of the [Python documentation](https://docs.python.org/3/library/exceptions.html#exception-hierarchy).
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/40-exceptions/70-best-practices.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Best Practices"
3 | date: 2019-03-10T19:15:44-07:00
4 | draft: false
5 | weight: 7
6 | ---
7 |
8 | ### Catch More Specific Exceptions First
9 |
10 | Remember, your `except` handlers are evaluated in order, so be sure to put more specific exceptions first. For example:
11 |
12 | ```python
13 | >>> try:
14 | ... my_value = 3.14 / 0
15 | ... except ArithmeticError:
16 | ... print("We had a general math error")
17 | ... except ZeroDivisionEror:
18 | ... print("We had a divide-by-zero error")
19 | ...
20 | We had a general math error
21 | ```
22 |
23 | When we tried to divide by zero, we inadvertently raised a ZeroDivisionError. However, because ZeroDivisionError is a subclass of ArithmeticError, and `except ArithemticError` came first, the information about our specific error was swallowed by the `except ArithemticError` handler, and we lost more detailed information about our error.
24 |
25 | ### Don't Catch `Exception`
26 |
27 | It's bad form to catch the general `Exception` class. This will catch every type of exception that subclasses the `Exception` class, which is almost all of them. You may have errors that you don't care about, and don't affect the operation of your program, or maybe you're dealing with a flaky API and want to swallow errors and retry. By catching `Exception`, you run the risk of hitting an unexpected exception that your program actually can't recover from, or worse, swallowing an important exception without properly logging it - a huge headache when trying to debug programs that are failing in weird ways.
28 |
29 |
30 | ### Definitely don't catch `BaseException`
31 |
32 | Catching `BaseException` is a really bad idea, because you'll swallow every type of Exception, including `KeyboardInterrupt`, the exception that causes your program to exit when you send a SIGINT (Ctrl-C). Don't do it.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/40-exceptions/90-custom-exceptions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Custom Exceptions"
3 | date: 2019-03-10T19:16:01-07:00
4 | draft: false
5 | weight: 9
6 | ---
7 |
8 | As we mentioned, exceptions are just regular classes that inherit from the `Exception` class. This makes it super easy to create our own custom exceptions, which can make our programs easier to follow and more readable. An exception need not be complicated, just inherit from `Exception`:
9 |
10 | ```python
11 | >>> class MyCustomException(Exception):
12 | ... pass
13 | ...
14 | >>> raise MyCustomException()
15 | Traceback (most recent call last):
16 | File "", line 1, in
17 | __main__.MyCustomException
18 | ```
19 |
20 | It's OK to have a custom `Exception` subclass that only `pass`-es - your exception doesn't need to do anything fancy to be useful. Having custom exceptions - tailored to your specific use cases and that you can raise and catch in specific circumstances - can make your code much more readable and robust, and reduce the amount of code you write later to try and figure out what exactly went wrong.
21 |
22 | Of course, you can get as fancy as you want. You can send additional information, like messages, to your exceptions. Just add an `__init__()` method to your exception class, with whatever arguments you want.
23 |
24 | ```python
25 | class IncorrectValueError(Exception):
26 | ... def __init__(self, value):
27 | ... message = f"Got an incorrect value of {value}"
28 | ... super().__init__(message)
29 | ...
30 | >>> my_value = 9999
31 | >>> if my_value > 100:
32 | ... raise IncorrectValueError(my_value)
33 | ...
34 | Traceback (most recent call last):
35 | File "", line 2, in
36 | __main__.IncorrectValueError: Got an incorrect value of 9999
37 | ```
38 |
39 | `Exception` takes an optional string argument message that gets printed with your exception. We pass our erroneous value to our `IncorrectValueError` object, which constructs a special message and passes it its parent class, `Exception`, via `super().__init__()`. The custom message string, along with the value for context, gets printed along with our error traceback.
40 |
41 | ### A Custom Exception for our GitHub API app
42 |
43 | If we wanted to write a custom Exception for our GitHub API app, it might look something like this.
44 |
45 | ```python
46 | class GitHubApiException(Exception):
47 |
48 | def __init__(self, status_code):
49 | if status_code == 403:
50 | message = "Rate limit reached. Please wait a minute and try again."
51 | else:
52 | message = f"HTTP Status Code was: {status_code}."
53 |
54 | super().__init__(message)
55 | ```
56 |
57 | Notice how it takes the HTTP status code into account, and displays a custom error message for the 403, rate limited reached status code.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/40-exceptions/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Exceptions"
3 | date = 2019-03-03T11:57:29-08:00
4 | weight = 40
5 | chapter = true
6 | pre = "4. "
7 | draft = false
8 | +++
9 |
10 | ### Chapter 4
11 |
12 | # Exceptions
13 |
14 | In this chapter you'll learn all about Exceptions in Python. We'll start by reviewing the exception hierarchy, raising exceptions, examining `try` and `catch`, and finally how to create our own Exception classes.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/50-libraries-modules/10-standard-library.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Standard Library"
3 | date: 2019-03-10T19:16:56-07:00
4 | draft: false
5 | weight: 1
6 | ---
7 |
8 | Python has always had a "batteries included" philosophy - having a rich and versatile standard library which is immediately available, without making the user download separate packages. This is thought to have contributed to Python's early success. No matter what you're trying to accomplish, there's probably a built-in library that can help you do what you want.
9 |
10 | The downside to this is that the standard libraries need to maintain backwards compatibility. Some were quick hacks, hard to use, poorly designed and now impossible to fix, or have simply been rendered obsolete. Luckily, Python also makes it easy to install and use external libraries - we'll cover this later.
11 |
12 |
13 | ### The Standard Library
14 |
15 | There are some great libraries included with Python that you'll probably end up seeing or using frequently. `sys` provides system-specific parameters and functions, such as `exit()`. `os` has miscellaneous operating system interfaces, and provides the excellent `os.path` submodule for handling file paths on any operating system. `math` gives you all the advanced math function. `json` is an easy-to-use json parser and encoder. Python even gives you built-in libraries for database access, logging, internet protocols, multimedia, debugging, and even libraries for extending Python itself. The full list of standard libraries can be found in the [Python documentation](https://docs.python.org/3/library/).
16 |
17 | As a quick example, let's look at Python's `datetime` library. You can easily make a `datetime` object that represents any given point in time. For example:
18 |
19 | ```python
20 | >>> import datetime
21 | >>> right_now = datetime.datetime.now()
22 | >>> print(right_now)
23 | 2019-03-17 13:41:10.994700
24 | >>> repr(right_now)
25 | 'datetime.datetime(2019, 3, 17, 13, 41, 10, 994700)'
26 | ```
27 |
28 | We can even make a `datetime` object for an arbitrary date, and subtract it from right now to get a `timedelta` object:
29 |
30 | ```python
31 | >>> new_years = datetime.datetime(2019, 1, 1, 0, 0)
32 | >>> print(new_years)
33 | 2019-01-01 00:00:00
34 | >>> delta = right_now - new_years
35 | >>> print(delta)
36 | 75 days, 13:41:10.994700
37 | ```
38 |
39 | We can easily see that it's been over 75 days from `new_years` until `right_now`. We'll come back to `datetime` later in this chapter.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/50-libraries-modules/30-modules-and-imports.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Modules and Imports"
3 | date: 2019-03-10T19:16:35-07:00
4 | draft: false
5 | weight: 3
6 | ---
7 |
8 | Python has a simple package structure. Any directory with a file named `__init__.py` can be considered a Python module.
9 |
10 | {{% notice info %}}
11 | Note: a `__init__.py` file is no longer *required* for Python 3 modules, but it's still supported and can be useful.
12 | {{% /notice %}}
13 |
14 | For example, let's make a basic function and start a new module to house it:
15 |
16 | ```python
17 | def add_numbers(x, y):
18 | return x + y
19 | ```
20 |
21 | Let's put our function in a file called `__init__.py` and place it in a folder called `my_math_functions`. Now, as long as the folder `my_math_functions` is somewhere in our `PYTHONPATH`, we can `import my_math_functions` and reach `add_numbers()`. If we start our REPL from the folder that contains `my_math_functions`, we can import it:
22 |
23 | ```python
24 | >>> import my_math_functions
25 | >>> my_math_functions.add_numbers(1, 2)
26 | 3
27 | ```
28 |
29 | ### Best Practices
30 |
31 | There a few different ways to import modules or even just specific objects from modules. You can import *everything* from a module into the local namespace using `*`:
32 |
33 | ```python
34 | >>> from my_math_functions import *
35 | >>> add_numbers(1, 2)
36 | 3
37 | ```
38 |
39 | This isn't a good practice, because it's hard to tell where a specific function is coming from without the namespace context. Also, function names can conflict, and this can make things very difficult to debug.
40 |
41 | Better is to import functions specifically:
42 |
43 | ```python
44 | >>> from my_math_functions import add_numbers
45 | >>> add_numbers(1, 2)
46 | 3
47 | ```
48 |
49 | This make things a little clearer, as we can look at the top and see where the `add_number()` function came from. However, an even better way is to just import the module and use it in calls to maintain the namespace context:
50 |
51 | ```python
52 | >>> import my_math_functions
53 | >>> my_math_functions.add_numbers(1, 2)
54 | 3
55 | ```
56 |
57 | This can be slightly more verbose, but unless it makes your function calls ridiculously long, it generally makes things much easier to debug.
58 |
59 | {{% notice tip %}}
60 | You can use the `as` keyword to make things a little easier on yourself.
61 | {{% /notice %}}
62 |
63 | ```python
64 | >>> import my_math_functions as mmf
65 | >>> mmf.add_numbers(1, 2)
66 | 3
67 | ```
68 |
69 | ### PYTHONPATH
70 |
71 | What is the `PYTHONPATH` we mentioned earlier? This is a list of paths on your system where Python will look for packages. Python will always look first in the working directory (the folder you're in when you start the REPL or run your program), so if your module folder is there, you can import it. You can also install your modules just like any other external modules, using a `setup.py` file. It's also possible to change or add paths to your `PYTHONPATH` list if you need to store modules elsewhere, but this isn't a very portable solution.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/50-libraries-modules/50-pypi.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "PyPI"
3 | date: 2019-03-10T19:17:03-07:00
4 | draft: false
5 | weight: 5
6 | ---
7 |
8 | PyPI (the Python Package Index) is an awesome service that helps you find and install software developed and shared by the Python community. Almost every user-contributed Python package has been published to PyPI. You can browse the site at [pypi.org](https://pypi.org/) but most of the time you will probably interact with it through Python's `pip` tool.
9 |
10 | ### Basic Usage
11 |
12 | You can use the `pip` tool to install the latest version of a module and its dependencies from the Python Packaging Index:
13 |
14 | ```bash
15 | (env) $ python -m pip install SomePackage
16 | ```
17 |
18 |
19 | ### Know your Packages
20 |
21 | There are a lot of packages on PyPI, and they're not always up-to-date. Sometimes it helps to look at a package before installing it. Simply search for a package name on PyPI.org - for example, here's the page for the [redis package](https://PyPI.org/project/redis/). If you follow the Homepage link, you'll be taken to the project's [GitHub page](https://github.com/andymccurdy/redis-py), where you can see that the latest commit was very recently. So you know this package is actively maintained, and will probably work in your up-to-date version of Python.
22 |
23 | {{% notice warning %}}
24 | When you're first starting out, it's a good idea to copy the `pip install` text from the website, otherwise bad actors could take advantage of your typos.
25 | {{% /notice %}}
26 |
27 |
28 | We'll practice installing a package in the exercise for this chapter.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/50-libraries-modules/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Libraries and Modules"
3 | date = 2019-03-03T12:07:12-08:00
4 | weight = 50
5 | chapter = true
6 | draft = false
7 | pre = "5. "
8 | +++
9 |
10 | ### Chapter 5
11 |
12 | # Libraries and Modules
13 |
14 | The Python language was designed to be "batteries included" -- it has a rich and versatile standard library which is immediately available, without making the user download separate packages. This has given the Python language a head start in many projects. Let's explore some of the helpful packages in the standard library, and learn how to make our own modules.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/60-command-line-tools/30-accepting-user-input.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Accepting User Input"
3 | date: 2019-03-10T19:27:09-07:00
4 | draft: false
5 | weight: 3
6 | ---
7 |
8 | ### Accepting Command Line Arguments
9 |
10 | To accept basic arguments from the command line, we can use `sys.argv`. `argv` is a list that gets passed in to your program that contains whatever arguments your program was started with. Start a new Python file called `cli_exercise.py` and enter the following:
11 |
12 | ```python
13 | import sys
14 |
15 | args = sys.argv
16 |
17 | print(args)
18 | ```
19 |
20 | Now run it:
21 |
22 | ```bash
23 | (env) $ python cli_exercise.py
24 | ['cli_exercise.py']
25 | ```
26 |
27 | You should see a list with one item: the name of your program. Pass in additional arguments by adding them after your program name on the command line, separated by spaces:
28 |
29 | ```bash
30 | python cli_exercise.py argument1 argument2 "hello world"
31 | ['cli_exercise.py', 'argument1', 'argument2', 'hello world']
32 | ```
33 |
34 | Note that the name of the file you're running is rarely useful, so it's common to see this omitted with using slices, for example `sys.argv[1:]`
35 |
36 | {{% notice warning %}}
37 | `sys.argv` is never empty - the first element in the list will always be the name of the Python file you're running.
38 | {{% /notice %}}
39 |
40 |
41 | ### Accepting User Input with `input`
42 |
43 | You can also accept user data inside a running program by using `input()`. Let's make a simple interactive command line program that asks for a user's name and birthday:
44 |
45 | ```python
46 | name = input("Hello, what is your name? ")
47 |
48 | birthday_string = input(f"Hello {name}. Please enter your birthday in MM/DD/YYYY format: ")
49 |
50 | print(f"Hello {name}. Your birthday is on {birthday_string}.")
51 | ```
52 |
53 | ```bash
54 | (env) $ python cli_exercise.py
55 | Hello, what is your name? Floyd
56 | Hello Floyd. Please enter your birthday in MM/DD/YYYY format: 01/20/1990
57 | Hello Floyd. Your birthday is on 01/20/1990.
58 | ```
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/60-command-line-tools/90-exercise.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Practice"
3 | date = 2019-01-25T15:07:04-06:00
4 | weight = 200
5 | draft = false
6 | pre = "⭐️ "
7 | +++
8 |
9 | ## Accepting User Input with Args
10 |
11 | To accept basic arguments from the command line, we can use `sys.argv`. Start a new Python file called `cli_exercise.py` and enter the following.
12 |
13 | ```python
14 | import sys
15 |
16 | args = sys.argv
17 |
18 | print(args)
19 | ```
20 |
21 | Then, run it from the command line:
22 |
23 | ```bash
24 | (env) $ python cli_exercise.py
25 | ```
26 |
27 |
28 | {{%expand "Here's what you should have seen on your command line:" %}}
29 |
30 | ```bash
31 | (env) $ python cli_exercise.py
32 | ['cli_exercise.py']
33 | ```
34 | {{% /expand%}}
35 |
36 | You should see a list with one item: the name of your program. Pass in additional arguments by adding them after your program name on the command line, separated by spaces:
37 |
38 | ```bash
39 | (env) $ python cli_exercise.py argument1 argument2 "hello world"
40 | ```
41 |
42 | {{%expand "Here's what you should have seen on your command line:" %}}
43 |
44 | ```bash
45 | (env) $ python cli_exercise.py argument1 argument2 "hello world"
46 | ['cli_exercise.py', 'argument1', 'argument2', 'hello world']
47 | ```
48 |
49 | {{% /expand%}}
50 |
51 | Note that the name of the file you're running is rarely useful, so it's common to see this omitted with using slices, for example `sys.argv[1:]`
52 |
53 | ## Accepting User Input with `input`
54 |
55 | You can also accept user data inside a running program by using `input()`. Let's make a simple interactive command line program that asks for a user's name and birthday. Call it `cli_exercise_input.py`. Use `input()` to get the user's name and birthday, and greet the user (call `strip()` on their name to remove any extra whitespace).
56 |
57 | {{%expand "You should have written something like this:" %}}
58 |
59 | ```python
60 | name = input("Hello, what is your name? ")
61 |
62 | birthday_string = input(f"Hello {name.strip()}. Please enter your birthday in MM/DD/YYYY format: ")
63 |
64 | print(f"Hello {name}. Your birthday is on {birthday_string}.")
65 | ```
66 | {{% /expand%}}
67 |
68 | {{%expand "Here's what you should have seen on your command line:" %}}
69 |
70 | ```bash
71 | (env) $ python cli_exercise_input.py
72 | Hello, what is your name? Floyd
73 | Hello Nina. Please enter your birthday in MM/DD/YYYY format: 01/20/1990
74 | Hello Floyd. Your birthday is on 01/20/1990.
75 | ```
76 |
77 | {{% /expand%}}
78 |
79 | ### Optional Advanced Exercise
80 |
81 | {{% notice note %}}
82 | If you thought this exercise was a breeze, try this optional advanced exercises.
83 | {{% /notice %}}
84 |
85 |
86 | Refactor the final exercise from Intro to Python, using custom exceptions and a class to store the information about a GitHub Repo. Accept the list of languages as user input.
87 |
88 | You can see an example implementation in the repo for this course at [git.io/python3](https://git.io/python3)
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/60-command-line-tools/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Writing Command Line Tools"
3 | date = 2019-03-03T11:56:49-08:00
4 | weight = 60
5 | chapter = true
6 | draft = false
7 | pre = "6. "
8 | +++
9 |
10 | ### Chapter 6
11 |
12 | # Command Line Tools
13 |
14 | Learn how to write command line tool scripts in Python that accept input from a user.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/70-tests/10-concept.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Concept"
3 | date: 2019-03-10T19:30:29-07:00
4 | draft: false
5 | weight: 1
6 | ---
7 |
8 | Unit testing is a software testing method by which individual functions are tested in an automated fashion to determine if they are fit for use. Automated unit testing not only helps you discover and fix bugs quicker and easier than if you weren't testing, but by writing them alongside or even *before* your functions, they can help you write cleaner and more bug-free code from the very start.
9 |
10 |
11 | ### Types of Tests
12 |
13 | There are several different kinds of automated tests that can be performed at different abstraction levels.
14 |
15 | * Unit tests operate on the smallest testable unit of code, usually a function that performs a single action or operation.
16 | * Integration tests check to see if different units or modules of code work together as a group.
17 | * Functional tests operate on units of functionality, to make sure a specific function of the software is working, which may involve several units of software or whole systems working together.
18 |
19 | For this class, we'll just be focusing on unit tests.
20 |
21 |
22 | ### Tests in the Real World™
23 |
24 | How is this helpful in the real world? Many companies that invest in software development maintain a CI/CD (Continuous Integration or Continuous Deployment) pipeline. This usually involves extensive unit tests, integration tests, and maybe even functional tests, which are set up to run automatically after (and sometimes even *before*) code is committed. If the tests fail, deployment can be stopped and the developers get notified before broken code ever makes it to production servers. This can be complicated to set up properly, but saves an enormous amount of time in the long run, and helps to keep bugs from ever reaching your users.
25 |
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/70-tests/30-assertions.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Assertions"
3 | date: 2019-03-10T19:30:41-07:00
4 | draft: false
5 | weight: 3
6 | ---
7 |
8 | Python comes with a handy-dandy `assert` keyword that you can use for simple sanity checks. An assertion is simply a boolean expression that checks if its conditions return true or not. If the assertion is true, the program continues. If it's false, it throws an `AssertionError`, and your program will stop. Assertions are also a great debugging tool, as they can stop your program in exactly the spot where an error has occurred. This is great for rooting out unreliable data or faulty assumptions.
9 |
10 | To make an assertion, just use the `assert` keyword followed by a condition that should be `True`:
11 |
12 | ```python
13 | >>> input_value = 25
14 | >>> assert input_value > 0
15 | ```
16 |
17 | If our assertion fails, however:
18 |
19 | ```python
20 | >>> input_value = 25
21 | >>> assert input_value > 100
22 | Traceback (most recent call last):
23 | File "", line 1, in
24 | AssertionError
25 | ```
26 |
27 | ### `assert` Is For Sanity Checks, Not For Production!
28 |
29 | Assertions are great for simple self-checks and sanity tests. You shouldn't, however, use assertions for failure cases that can occur because of bad user input or operating system/environment failures, such as a file not being found. These situations are much better suited to an exception or an error message.
30 |
31 | {{% notice warning %}}
32 | Assertions can be disabled at run time, by starting the program with `python -O`, so you shouldn't rely on assertions to run in production code. Don't use them for validation!
33 | {{% /notice %}}
34 |
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/70-tests/90-exercise.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Practice"
3 | date = 2019-01-25T15:07:04-06:00
4 | weight = 10
5 | draft = false
6 | pre = "⭐️ "
7 | +++
8 |
9 | ## Tests
10 |
11 | Python comes with a very easy-to-use `unittest` library built in. Write a simple function that accepts two numbers, and returns `True` if the first number is evenly divisible by the second.
12 |
13 | ```python
14 | def divisible_by(check_number, divisor):
15 | return check_number % divisor == 0
16 | ```
17 |
18 | Save your file as `divisible.py`. In a second file called `test_divisible.py`, create a `TestCase` using the `unittest` framework and use asserts to verify that the `divisible_by()`function returns the correct result. Don't forget to import your `divisible_by()` function.
19 |
20 | ```python
21 | import unittest
22 | from divisible import divisible_by
23 |
24 | class TestCase(unittest.TestCase):
25 |
26 | def test_divisible_by(self):
27 | self.assertTrue(divisible_by(10, 2))
28 | self.assertTrue(divisible_by(10, 3))
29 |
30 |
31 | if __name__ == '__main__':
32 | unittest.main()
33 | ```
34 |
35 | Name your file `test_divisible.py` and run it:
36 |
37 | ```bash
38 | (env) $ python test_divisible.py --verbose
39 | ```
40 |
41 | {{%expand "Here's what you should have seen on your command line:" %}}
42 |
43 | ```bash
44 | (env) $ python test_divisible.py --verbose
45 | test_divisible_by (__main__.TestCase) ... FAIL
46 |
47 | ======================================================================
48 | FAIL: test_divisible_by (__main__.TestCase)
49 | ----------------------------------------------------------------------
50 | Traceback (most recent call last):
51 | File "test_divisible.py", line 8, in test_divisible_by
52 | self.assertTrue(divisible_by(10, 3))
53 | AssertionError: False is not true
54 |
55 | ----------------------------------------------------------------------
56 | Ran 1 test in 0.001s
57 |
58 | FAILED (failures=1)
59 | ```
60 | {{% /expand%}}
61 |
62 | You should have gotten an error: `AssertionError: False is not true` caused by `self.assertTrue(divisible_by(10, 3))`. Makes sense, because 10 is not evenly divisible by 3.
63 |
64 | {{% notice tip %}}
65 | Change `self.assertTrue` to `self.assertFalse` and your test should pass.
66 | {{% /notice %}}
67 |
68 | ```bash
69 | (env) $ python test_divisible.py --verbose
70 | test_divisible_by (__main__.TestCase) ... ok
71 |
72 | ----------------------------------------------------------------------
73 | Ran 1 test in 0.000s
74 |
75 | OK
76 | ```
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/70-tests/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Tests"
3 | date = 2019-03-03T12:00:04-08:00
4 | weight = 70
5 | chapter = true
6 | draft = false
7 | pre = "7. "
8 | +++
9 |
10 | ### Chapter 7
11 |
12 | # Testing in Python
13 |
14 | Tests are a cornerstone of a solid Python program. Thankfully, because of Python's "batteries included" philosophy, all the tools we need for unit testing are included in the standard library. Let's learn the basics of Unit Testing.
15 |
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/80-web-frameworks/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Web Frameworks"
3 | date = 2019-03-03T12:00:11-08:00
4 | weight = 80
5 | chapter = true
6 | draft = false
7 | pre = "8. "
8 | +++
9 |
10 | ### Chapter 8
11 |
12 | # Web Frameworks
13 |
14 | In this final chapter, we'll learn about web frameworks, and practice all our new Python knowledge by building a basic web application with unit tests using Python and the `flask` framework.
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/80-web-frameworks/images/request-response.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/content/03-intermediate-python/80-web-frameworks/images/request-response.jpeg
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/90-Conclusion/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: "Wrapping Up"
3 | date: 2019-02-10T18:39:32-08:00
4 | draft: false
5 | ---
6 |
7 | ## Source Control
8 |
9 | I highly recommend that you use source control while working on your Python projects. GitHub is a popular and free option.
10 |
11 | Source control lets you track changes to your project. You can use that to your advantage to commit early and often and track changes to your project.
12 |
13 | If you're not familiar with how to use git or GitHub, you can watch my [Git In-depth Frontend Masters class](https://frontendmasters.com/courses/git-in-depth/). For Python projects, make sure that you use the correct `.gitignore` file. GitHub provides a [free template that you can use](https://github.com/github/gitignore/blob/master/Python.gitignore).
14 |
15 | ## Next Steps
16 |
17 | Now you know the basics, just enough to get started with working with APIs in Python with the `requests` library. You know just enough to see how powerful Python can be. You can chain all of these requests together into a fully functioning program that does so much more.
18 |
19 | The next topics to study are:
20 | * [How to authenticate to APIs](http://docs.python-requests.org/en/master/user/authentication/)
21 | * How to use the other HTTP methods, just as POST to create resources, or PUT to update them
22 | * Read the [requests Quick Start Guide](http://docs.python-requests.org/en/master/user/quickstart/)
23 |
24 | ## Additional Resources
25 |
26 | * [Flask Mega Tutorial](https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world) - For learning the A-Z of Python web apps
27 | * [Hitchhikers Guide to Python](https://docs.python-guide.org/) - free Book
28 | * Watch the video for this course - [Intro to Python](https://frontendmasters.com/workshops/intro-to-python/) & [Intermediate Python](https://frontendmasters.com/workshops/intermediate-python/)
--------------------------------------------------------------------------------
/website/content/03-intermediate-python/_index.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "Intermediate Python"
3 | date = 2019-03-03T11:55:16-08:00
4 | weight = 3
5 | chapter = true
6 | draft = false
7 | pre = "Day 2. "
8 | +++
9 |
10 | ### Day 2
11 |
12 | # Intermediate Python
13 |
14 | During day two, we'll start getting more comfortable with some of the more advanced aspects of Python, like classes, list comprehensions, and the standard library. At the end of the day, you'll know enough to build a small interactive API using the Flask web framework.
15 |
16 | {{% notice tip %}}
17 | To fully participate in todays class, you must have VS Code set up locally, along with Python version >= 3.7. You must be familiar with all the concepts from Day 1, including running Python programs, simple and complex types, boolean logic, control statements, and looping. If you're not sure, start with [Day 1](../02-introduction-to-python).
18 | {{% /notice %}}
19 |
20 | # Day 2 Overview
21 |
22 | By coding along with me in this workshop, you'll:
23 |
24 | - Use object-oriented programming to organize your code.
25 | - Diagnose problems in your Python programs by understanding Exceptions.
26 | - Work with new features in Python3 that make Python easier than ever, such as f-strings.
27 | - Learn about generators, a Python feature that allows you to loop over large data sets in a memory efficient way.
28 | - Learn how to build interactive APIs and websites efficiently using the Flask web framework.
--------------------------------------------------------------------------------
/website/content/_index.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Learn Python
3 | weight: 1
4 | chapter: true
5 | ---
6 |
7 | # Learn Python
8 |
9 | Welcome to Introduction and Intermediate Python, recorded for Frontend Masters.
10 |
11 | Created by Nina Zakharenko. @nnja .
12 |
13 | Watch the accompanying screencast via subscription on [FrontendMasters.com](https://frontendmasters.com/teachers/nina-zakharenko/).
14 |
15 | {{< figure src="/images/fem.png" title="Watch the course" link="https://frontendmasters.com/courses/python/">}}
16 |
17 | Stay up to date with me on LinkedIn , or to contact me directly, please send me an email at learnpython@nnja.io .
18 |
19 | You can find the content and exercises on the Github repo .
20 |
21 |
22 | The course content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License .
23 |
24 | I'd like to encourage learning individuals to learn Python from the course material for free, but if you'd like to use the material for your own workshop or for commercial use, please consider supporting my work and [watch the screencast](https://frontendmasters.com/teachers/nina-zakharenko/) instead.
--------------------------------------------------------------------------------
/website/content/credits.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Credits
3 | disableToc: true
4 | ---
5 |
6 |
7 | ### Themes
8 | * Special thanks to the hugo [learn theme](https://github.com/matcornic/hugo-theme-learn).
9 |
10 | ### Tooling
11 | * [Hugo](https://gohugo.io/)
12 |
13 | ### Other
14 | * [Pixel Art](https://www.pixilart.com/art/python-robotics-pixel-art-5c4a112fde67eab)
15 |
16 | ### CSS Styles For Final Exercise
17 | * [Buttons](https://codepen.io/wilder_taype/pen/LeoQEb)
18 | * [Checkboxes](https://codepen.io/wilder_taype/pen/pNXwMW)
19 | * [Tables](https://codepen.io/gmb/pen/xVGYZw)
20 | * [Error Page](https://codepen.io/akashrajendra/pen/JKKRvQ)
21 |
22 |
23 | ##### Special thanks to my [❤️ Max](http://twitter.com/mhenstell) for moral support while I worked on this class.
--------------------------------------------------------------------------------
/website/layouts/partials/logo.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/layouts/partials/menu-footer.html:
--------------------------------------------------------------------------------
1 | Built with the Learn theme.
2 |
3 | The course content is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License .
--------------------------------------------------------------------------------
/website/layouts/partials/meta_twitter.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/website/layouts/shortcodes/todo.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/public/categories/index.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Categories on My New Hugo Site
5 | http://example.org/categories/
6 | Recent content in Categories on My New Hugo Site
7 | Hugo -- gohugo.io
8 | en-us
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/website/public/index.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | My New Hugo Site
5 | http://example.org/
6 | Recent content on My New Hugo Site
7 | Hugo -- gohugo.io
8 | en-us
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/website/public/sitemap.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 | http://example.org/categories/
7 | 0
8 |
9 |
10 |
11 | http://example.org/
12 | 0
13 |
14 |
15 |
16 | http://example.org/tags/
17 | 0
18 |
19 |
20 |
--------------------------------------------------------------------------------
/website/public/tags/index.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Tags on My New Hugo Site
5 | http://example.org/tags/
6 | Recent content in Tags on My New Hugo Site
7 | Hugo -- gohugo.io
8 | en-us
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/website/static/_redirects:
--------------------------------------------------------------------------------
1 | # Redirect default subdomain to primary domain
2 | https://learnpython.netlify.com/* https://www.learnpython.dev/:splat 301!
--------------------------------------------------------------------------------
/website/static/code/cities.json:
--------------------------------------------------------------------------------
1 | [{
2 | "name": "New York",
3 | "pop": 8550405
4 | },
5 | {
6 | "name": "Los Angeles",
7 | "pop": 3971883
8 | },
9 | {
10 | "name": "Chicago",
11 | "pop": 2720546
12 | },
13 | {
14 | "name": "Houston",
15 | "pop": 2296224
16 | },
17 | {
18 | "name": "Philadelphia",
19 | "pop": 1567442
20 | }
21 | ]
--------------------------------------------------------------------------------
/website/static/code/day_one_class.py:
--------------------------------------------------------------------------------
1 | """
2 | A small Python program that uses the GitHub search API to list
3 | the top projects by language, based on stars.
4 |
5 | GitHub Search API documentation: https://developer.github.com/v3/search/
6 |
7 | Additional parameters for searching repos can be found here:
8 | https://help.github.com/en/articles/searching-for-repositories#search-by-number-of-stars
9 |
10 | Note: The API will return results found before a timeout occurs,
11 | so results may not be the same across requests, even with the same query.
12 |
13 | Requests to this endpoint are rate limited to 10 requests per
14 | minute per IP address.
15 | """
16 |
17 | import requests
18 |
19 | GITHUB_API_URL = "https://api.github.com/search/repositories"
20 |
21 |
22 | def create_query(languages, min_stars=50000):
23 | """
24 | Create the query string for the GitHub search API,
25 | based on the minimum amount of stars for a project, and
26 | the provided programming languages.
27 |
28 | An example search query looks like:
29 | stars:>50000 language:python language:javascript
30 | """
31 | query = f"stars:>{min_stars} "
32 |
33 | for language in languages:
34 | query += f"language:{language} "
35 |
36 | return query
37 |
38 |
39 | def repos_with_most_stars(languages, sort="stars", order="desc"):
40 | query = create_query(languages)
41 |
42 | # Define the parameters we want to be part of our URL
43 | parameters = {"q": query, "sort": sort, "order": order}
44 |
45 | # Pass in the query and the parameters as part of the request.
46 | response = requests.get(GITHUB_API_URL, params=parameters)
47 | status_code = response.status_code
48 |
49 | # Check if the rate limit was hit. Applies only for students running this code
50 | # in the in-person course.
51 | if status_code == 403:
52 | raise RuntimeError("Rate limit reached. Please wait a minute and try again.")
53 | if status_code != 200:
54 | raise RuntimeError(f"An error occurred. HTTP Status Code was: {status_code}.")
55 | else:
56 | response_json = response.json()
57 | records = response_json["items"]
58 | return records
59 |
60 |
61 | if __name__ == "__main__":
62 | languages = ["python", "javascript", "ruby"]
63 | results = repos_with_most_stars(languages)
64 |
65 | for result in results:
66 | language = result["language"]
67 | stars = result["stargazers_count"]
68 | name = result["name"]
69 |
70 | print(f"-> {name} is a {language} repo with {stars} stars.")
71 |
--------------------------------------------------------------------------------
/website/static/code/day_one_min.py:
--------------------------------------------------------------------------------
1 | """
2 | A small Python program that uses the GitHub search API to list
3 | the top projects by language, based on stars.
4 | """
5 |
6 | import requests
7 |
8 | GITHUB_API_URL = "https://api.github.com/search/repositories"
9 |
10 |
11 | def create_query(languages, min_stars=50000):
12 | query = f"stars:>{min_stars} "
13 |
14 | for language in languages:
15 | query += f"language:{language} "
16 |
17 | # a sample query looks like: "stars:>50 language:python language:javascript"
18 | return query
19 |
20 |
21 | def repos_with_most_stars(languages, sort="stars", order="desc"):
22 | query = create_query(languages)
23 | params = {"q": query, "sort": sort, "order": order}
24 |
25 | response = requests.get(GITHUB_API_URL, params=params)
26 |
27 | print(response.url)
28 | status_code = response.status_code
29 |
30 | if status_code != 200:
31 | raise RuntimeError(f"An error occurred. HTTP Code: {status_code}.")
32 | else:
33 | response_json = response.json()
34 | return response_json["items"]
35 |
36 |
37 | if __name__ == "__main__":
38 | languages = ["python", "javascript", "ruby"]
39 | results = repos_with_most_stars(languages)
40 |
41 | for result in results:
42 | language = result["language"]
43 | stars = result["stargazers_count"]
44 | name = result["name"]
45 |
46 | print(f"-> {name} is a {language} repo with {stars} stars.")
47 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/code/day_two_final_exercise.zip
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/app.py:
--------------------------------------------------------------------------------
1 | """
2 | A Simple Flask Web Application interface
3 | For viewing popular GitHub Repos sorted by stars using the
4 | GitHub Search API.
5 |
6 | To run:
7 | (env) $ python -m pip install -r requirements.txt
8 | (env) $ export FLASK_ENV=development; python3 -m flask run
9 | """
10 | from flask import Flask, render_template, request
11 |
12 | from repos.api import repos_with_most_stars
13 | from repos.exceptions import GitHubApiException
14 |
15 | app = Flask(__name__)
16 |
17 | available_languages = ["Python", "JavaScript", "Ruby", "Java"]
18 |
19 |
20 | @app.route('/', methods=['POST', 'GET'])
21 | def index():
22 | if request.method == 'GET':
23 | # Use the list of all languages
24 | selected_languages = available_languages
25 | elif request.method == 'POST':
26 | # Use the languages we selected in the request form
27 | selected_languages = request.form.getlist("languages")
28 |
29 | results = repos_with_most_stars(selected_languages)
30 |
31 | return render_template(
32 | 'index.html',
33 | selected_languages=selected_languages,
34 | available_languages=available_languages,
35 | results=results)
36 |
37 |
38 | @app.errorhandler(GitHubApiException)
39 | def handle_api_error(error):
40 | return render_template('error.html', message=error)
41 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/repos/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/code/day_two_final_exercise/repos/__init__.py
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/repos/api.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 | from repos.exceptions import GitHubApiException
4 | from repos.models import GitHubRepo
5 |
6 |
7 | GITHUB_API_URL = "https://api.github.com/search/repositories"
8 |
9 |
10 | def create_query(languages, min_stars):
11 | """
12 | Create the query string for the GitHub search API,
13 | based on the minimum amount of stars for a project, and
14 | the provided programming languages.
15 | """
16 | # Notice we are calling .strip() on each language,
17 | # to clear it of leading and trailing whitespace
18 | query = " ".join(f"language:{language.strip()}" for language in languages)
19 | query = query + f" stars:>{min_stars}"
20 | return query
21 |
22 |
23 | def repos_with_most_stars(languages, min_stars=40000, sort="stars", order="desc"):
24 | query = create_query(languages, min_stars)
25 | parameters = {"q": query, "sort": sort, "order": order}
26 | print(parameters)
27 | response = requests.get(GITHUB_API_URL, params=parameters)
28 |
29 | if response.status_code != 200:
30 | raise GitHubApiException(response.status_code)
31 |
32 | response_json = response.json()
33 | items = response_json["items"]
34 | return [GitHubRepo(item["name"], item["language"], item["stargazers_count"]) for item in items]
35 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/repos/exceptions.py:
--------------------------------------------------------------------------------
1 | """
2 | GitHub API Application: Custom Exception Classes
3 | """
4 |
5 | class GitHubApiException(Exception):
6 |
7 | def __init__(self, status_code):
8 | if status_code == 403:
9 | message = "Rate limit reached. Please wait a minute and try again."
10 | else:
11 | message = f"HTTP Status Code was: {status_code}."
12 |
13 | super().__init__("A GitHub API Error Occurred: " + message)
14 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/repos/models.py:
--------------------------------------------------------------------------------
1 | """
2 | GitHub API Application: Custom Model Classes
3 | """
4 |
5 | class GitHubRepo:
6 | """
7 | A class used to represent a single GitHub Repository.
8 | """
9 |
10 | def __init__(self, name, language, num_stars):
11 | self.name = name
12 | self.language = language
13 | self.num_stars = num_stars
14 |
15 | def __str__(self):
16 | return f"-> {self.name} is a {self.language} repo with {self.num_stars} stars."
17 |
18 | def __repr__(self):
19 | return f'GitHubRepo({self.name}, {self.language}, {self.num_stars})'
20 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/requirements.txt:
--------------------------------------------------------------------------------
1 | flask
2 | requests
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/static/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/code/day_two_final_exercise/static/favicon.png
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/static_files.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/code/day_two_final_exercise/static_files.zip
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/templates/error.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
{{message}}
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/templates/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Learn Python: Popular GitHub Repos (by ⭐️) With Flask
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
Languages
17 |
27 |
28 |
29 |
30 |
Popular GitHub Repos (by ⭐️)
31 |
32 |
33 |
34 | {% if not results %}
35 | No Results.
36 | {% else %}
37 |
38 | Name
39 | Language
40 | Number Stars
41 |
42 | {% endif %}
43 |
44 | {% for result in results %}
45 |
46 | {{result.name}}
47 | {{result.language}}
48 | {{result.num_stars}}
49 |
50 | {% endfor %}
51 |
52 |
53 |
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/test.py:
--------------------------------------------------------------------------------
1 | import repos.api
2 | import repos.exceptions
3 |
4 | import unittest
5 |
6 | class TestCreateQuery(unittest.TestCase):
7 |
8 | def test_create_query(self):
9 | test_languages = ["Python", "Ruby", "Java"]
10 | test_min_stars = 10000
11 |
12 | expected = "language:Python language:Ruby language:Java stars:>10000"
13 | result = repos.api.create_query(test_languages, test_min_stars)
14 |
15 | self.assertEqual(result, expected, "Unexpected result from create_query")
16 |
17 |
18 | class TestGitHubApiException(unittest.TestCase):
19 |
20 | def test_exception_403(self):
21 | status_code = 403
22 | exception = repos.exceptions.GitHubApiException(status_code)
23 | self.assertTrue("Rate limit" in str(exception), "'Rate limit' not found")
24 |
25 | def test_exception_500(self):
26 | status_code = 500
27 | exception = repos.exceptions.GitHubApiException(status_code)
28 | self.assertTrue(str(status_code) in str(exception))
29 |
30 |
31 | if __name__ == "__main__":
32 | unittest.main()
33 |
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/code/day_two_final_exercise/tests/__init__.py
--------------------------------------------------------------------------------
/website/static/code/day_two_final_exercise/tests/tests.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/code/day_two_final_exercise/tests/tests.py
--------------------------------------------------------------------------------
/website/static/code/dayone.py:
--------------------------------------------------------------------------------
1 | """
2 | A small Python program that uses the GitHub search API to list
3 | the top projects by language, based on stars.
4 |
5 | GitHub Search API documentation: https://developer.github.com/v3/search/
6 |
7 | Additional parameters for searching repos can be found here:
8 | https://help.github.com/en/articles/searching-for-repositories#search-by-number-of-stars
9 |
10 | Note: The API will return results found before a timeout occurs,
11 | so results may not be the same across requests, even with the same query.
12 |
13 | Requests to this endpoint are rate limited to 10 requests per
14 | minute per IP address.
15 | """
16 |
17 | import requests
18 |
19 | GITHUB_API_URL = "https://api.github.com/search/repositories"
20 |
21 |
22 | def create_query(languages, min_stars=50000):
23 | """
24 | Create the query string for the GitHub search API,
25 | based on the minimum amount of stars for a project, and
26 | the provided programming languages.
27 |
28 | An example search query looks like:
29 | stars:>50000 language:python language:javascript
30 | """
31 | query = f"stars:>{min_stars} "
32 |
33 | for language in languages:
34 | query += f"language:{language} "
35 |
36 | return query
37 |
38 |
39 | def repos_with_most_stars(languages, sort="stars", order="desc"):
40 | query = create_query(languages)
41 |
42 | # Define the parameters we want to be part of our URL
43 | parameters = {"q": query, "sort": sort, "order": order}
44 |
45 | # Pass in the query and the parameters as part of the request.
46 | response = requests.get(GITHUB_API_URL, params=parameters)
47 | status_code = response.status_code
48 |
49 | if status_code != 200:
50 | raise RuntimeError(
51 | f"An error occurred. HTTP Status Code was: {status_code}.")
52 | else:
53 | response_json = response.json()
54 | records = response_json["items"]
55 | return records
56 |
57 |
58 | if __name__ == "__main__":
59 | languages = ["python", "javascript", "ruby"]
60 | results = repos_with_most_stars(languages)
61 |
62 | for result in results:
63 | language = result["language"]
64 | stars = result["stargazers_count"]
65 | name = result["name"]
66 |
67 | print(f"-> {name} is a {language} repo with {stars} stars.")
68 |
--------------------------------------------------------------------------------
/website/static/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/images/favicon.png
--------------------------------------------------------------------------------
/website/static/images/fem.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/images/fem.png
--------------------------------------------------------------------------------
/website/static/images/me.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/images/me.jpg
--------------------------------------------------------------------------------
/website/static/images/snake-cropped.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/images/snake-cropped.png
--------------------------------------------------------------------------------
/website/static/images/snake-scaled.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/images/snake-scaled.png
--------------------------------------------------------------------------------
/website/static/images/snake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/images/snake.png
--------------------------------------------------------------------------------
/website/static/images/twittercard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/static/images/twittercard.png
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | public/
3 | exampleSite/public
4 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/.grenrc.yml:
--------------------------------------------------------------------------------
1 | ---
2 | dataSource: "prs"
3 | prefix: "v"
4 | onlyMilestones: false
5 | changelogFilename: "CHANGELOG.md"
6 | includeMessages: "all"
7 | ignoreIssuesWith:
8 | - "support"
9 | ignoreLabels:
10 | - "duplicate"
11 | - "invalid"
12 | - "wontfix"
13 | groupBy:
14 | New features:
15 | - "feature"
16 | Bug Fixes:
17 | - "bug"
18 | Enhancements:
19 | - "enhancement"
20 | Internationalisation:
21 | - "i18n"
22 | Theme Meta:
23 | - "meta"
24 | Uncategorised:
25 | - "closed"
26 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Grav
4 | Copyright (c) 2016 MATHIEU CORNIC
5 | Copyright (c) 2017 Valere JEANTET
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of
8 | this software and associated documentation files (the "Software"), to deal in
9 | the Software without restriction, including without limitation the rights to
10 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11 | the Software, and to permit persons to whom the Software is furnished to do so,
12 | subject to the following conditions:
13 |
14 | The above copyright notice and this permission notice shall be included in all
15 | copies or substantial portions of the Software.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/README.md:
--------------------------------------------------------------------------------
1 | # Hugo Learn Theme
2 |
3 | This repository contains a theme for [Hugo](https://gohugo.io/), based on great [Grav Learn Theme](https://learn.getgrav.org/).
4 |
5 | Visit the [theme documentation](https://learn.netlify.com/en/) to see what is going on. It is actually built with this theme.
6 |
7 | [](https://app.wercker.com/project/byKey/233466a2be73fcea400e7dc02ef6adf9)
8 | [](https://app.fossa.io/projects/git%2Bgithub.com%2Fmatcornic%2Fhugo-theme-learn?ref=badge_shield)
9 |
10 | ## Main features
11 |
12 | - Automatic Search
13 | - Multilingual mode
14 | - Unlimited menu levels
15 | - Automatic next/prev buttons to navigate through menu entries
16 | - Image resizing, shadow…
17 | - Attachments files
18 | - List child pages
19 | - Mermaid diagram (flowchart, sequence, gantt)
20 | - Customizable look and feel and themes variants
21 | - Buttons, Tip/Note/Info/Warning boxes, Expand
22 |
23 | ## Installation
24 |
25 | Navigate to your themes folder in your Hugo site and use the following commands:
26 |
27 | ```
28 | $ cd themes
29 | $ git clone https://github.com/matcornic/hugo-theme-learn.git
30 | ```
31 |
32 | Check that your Hugo version is minimum `0.25` with `hugo version`.
33 |
34 | 
35 |
36 | ## Usage
37 |
38 | - [Visit the documentation](https://learn.netlify.com/en/)
39 |
40 | ## Download old versions (prior to 2.0.0)
41 |
42 | If you need old version for compatibility purpose, either download [theme source code from releases](https://github.com/matcornic/hugo-theme-learn/releases) or use the right git tag. For example, with `1.1.0`
43 |
44 | - Direct download way: https://github.com/matcornic/hugo-theme-learn/archive/1.1.0.zip
45 | - Git way:
46 |
47 | ```shell
48 | cd themes/hugo-theme-learn
49 | git checkout tags/1.1.0
50 | ```
51 |
52 | For both solutions, the documentation is available at https://github.com/matcornic/hugo-theme-learn/releases/download/1.1.0/hugo-learn-doc-1.1.0.zip
53 |
54 | ## Credits
55 |
56 | Many thanks to [@vjeantet](https://github.com/vjeantet/) for the fork [docdock](https://github.com/vjeantet/hugo-theme-docdock). The v2 of this theme is mainly based on his work !
57 |
58 |
59 | ## License
60 | [](https://app.fossa.io/projects/git%2Bgithub.com%2Fmatcornic%2Fhugo-theme-learn?ref=badge_large)
61 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/archetypes/chapter.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "{{ replace .Name "-" " " | title }}"
3 | date = {{ .Date }}
4 | weight = 5
5 | chapter = true
6 | pre = "X. "
7 | +++
8 |
9 | ### Chapter X
10 |
11 | # Some Chapter title
12 |
13 | Lorem Ipsum.
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/archetypes/default.md:
--------------------------------------------------------------------------------
1 | +++
2 | title = "{{ replace .Name "-" " " | title }}"
3 | date = {{ .Date }}
4 | weight = 5
5 | +++
6 |
7 | Lorem Ipsum.
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/i18n/en.toml:
--------------------------------------------------------------------------------
1 | [Search-placeholder]
2 | other = "Search..."
3 |
4 | [Clear-History]
5 | other = "Clear History"
6 |
7 | [Attachments-label]
8 | other = "Attachments"
9 |
10 | [title-404]
11 | other = "Error"
12 |
13 | [message-404]
14 | other = "Woops. Looks like this page doesn't exist ¯\\_(ツ)_/¯."
15 |
16 | [Go-to-homepage]
17 | other = "Go to homepage"
18 |
19 | [Edit-this-page]
20 | other = "Edit this page"
21 |
22 | [Shortcuts-Title]
23 | other = "More"
24 |
25 | [Expand-title]
26 | other = "Expand me..."
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/i18n/es.toml:
--------------------------------------------------------------------------------
1 | [Search-placeholder]
2 | other = "Buscar..."
3 |
4 | [Clear-History]
5 | other = "Borrar Historial"
6 |
7 | [Attachments-label]
8 | other = "Adjuntos"
9 |
10 | [title-404]
11 | other = "Error"
12 |
13 | [message-404]
14 | other = "Ups. Parece que la página no existe ¯\\_(ツ)_/¯."
15 |
16 | [Go-to-homepage]
17 | other = "Ir al inicio"
18 |
19 | [Edit-this-page]
20 | other = "Editar esta página"
21 |
22 | [Shortcuts-Title]
23 | other = "Más"
24 |
25 | [Expand-title]
26 | other = "Expandir..."
27 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/i18n/fr.toml:
--------------------------------------------------------------------------------
1 | [Search-placeholder]
2 | other = "Rechercher..."
3 |
4 | [Clear-History]
5 | other = "Supprimer l'historique"
6 |
7 | [Attachments-label]
8 | other = "Pièces jointes"
9 |
10 | [title-404]
11 | other = "Erreur"
12 |
13 | [message-404]
14 | other = "Oups. On dirait que cette page n'existe pas ¯\\_(ツ)_/¯"
15 |
16 | [Go-to-homepage]
17 | other = "Vers la page d'accueil"
18 |
19 | [Edit-this-page]
20 | other = "Modifier la page"
21 |
22 | [Shortcuts-Title]
23 | other = "Aller plus loin"
24 |
25 | [Expand-title]
26 | other = "Déroulez-moi..."
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/i18n/id.toml:
--------------------------------------------------------------------------------
1 | [Search-placeholder]
2 | other = "Telusuri..."
3 |
4 | [Clear-History]
5 | other = "Bersihkan Riwayat"
6 |
7 | [Attachments-label]
8 | other = "Lampiran"
9 |
10 | [title-404]
11 | other = "Kesalahan"
12 |
13 | [message-404]
14 | other = "Oops. Sepertinya halaman ini tidak ada ¯\\_(ツ)_/¯."
15 |
16 | [Go-to-homepage]
17 | other = "Ke halaman depan"
18 |
19 | [Edit-this-page]
20 | other = "Edit halaman ini"
21 |
22 | [Shortcuts-Title]
23 | other = "Lainnya"
24 |
25 | [Expand-title]
26 | other = "Bentangkan..."
27 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/i18n/nl.toml:
--------------------------------------------------------------------------------
1 | [Search-placeholder]
2 | other = "Zoeken..."
3 |
4 | [Clear-History]
5 | other = "Wis geschiedenis"
6 |
7 | [Attachments-label]
8 | other = "Bijlagen"
9 |
10 | [title-404]
11 | other = "Error"
12 |
13 | [message-404]
14 | other = "Blijkbaar bestaat deze pagina niet ¯\\_(ツ)_/¯."
15 |
16 | [Go-to-homepage]
17 | other = "Naar startpagina"
18 |
19 | [Edit-this-page]
20 | other = "Deze pagina bewerken"
21 |
22 | [Shortcuts-Title]
23 | other = "Snelkoppelingen"
24 |
25 | [Expand-title]
26 | other = "Lees meer..."
27 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/i18n/pt.toml:
--------------------------------------------------------------------------------
1 | [Search-placeholder]
2 | other = "Procurar..."
3 |
4 | [Clear-History]
5 | other = "Limpar Histórico"
6 |
7 | [Attachments-label]
8 | other = "Anexos"
9 |
10 | [title-404]
11 | other = "Erro"
12 |
13 | [message-404]
14 | other = "Ops. Parece que a página não existe ¯\\_(ツ)_/¯."
15 |
16 | [Go-to-homepage]
17 | other = "Ir para o início"
18 |
19 | [Edit-this-page]
20 | other = "Editar esta página"
21 |
22 | [Shortcuts-Title]
23 | other = "Mais"
24 |
25 | [Expand-title]
26 | other = "Expandir..."
27 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/i18n/tr.toml:
--------------------------------------------------------------------------------
1 | [Search-placeholder]
2 | other = "Ara..."
3 |
4 | [Clear-History]
5 | other = "Geçmişi Temizle"
6 |
7 | [Attachments-label]
8 | other = "Ekler"
9 |
10 | [title-404]
11 | other = "Hata"
12 |
13 | [message-404]
14 | other = "Uups. Görünüşe göre böyle bir sayfa yok ¯\\_(ツ)_/¯"
15 |
16 | [Go-to-homepage]
17 | other = "Anasayfaya dön"
18 |
19 | [Edit-this-page]
20 | other = "Sayfayı düzenle"
21 |
22 | [Shortcuts-Title]
23 | other = "Dahası Var"
24 |
25 | [Expand-title]
26 | other = "Genişlet..."
27 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/images/screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/images/screenshot.png
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/images/tn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/images/tn.png
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/404.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ partial "meta.html" . }} {{ partial "favicon.html" . }} {{ .Scratch.Add "title" "" }}{{ if eq .Site.Data.titles .Title }}{{ .Scratch.Set "title" (index .Site.Data.titles .Title).title }}{{ else }}{{ .Scratch.Set "title" .Title}}{{end}}
6 | {{ .Scratch.Get "title" }}
7 |
8 | {{ $assetBusting := not .Site.Params.disableAssetsBusting }}
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | {{with .Site.Params.themeVariant}}
18 |
19 | {{end}}
20 |
35 | {{ partial "custom-header.html" . }}
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
{{T "title-404"}}
47 |
48 |
49 |
{{T "message-404"}}
50 |
51 |
{{T "Go-to-homepage"}}
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/_default/list.html:
--------------------------------------------------------------------------------
1 | {{ partial "header.html" . }}
2 |
3 | {{ .Content }}
4 |
5 |
11 |
12 | {{ partial "footer.html" . }}
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/_default/single.html:
--------------------------------------------------------------------------------
1 | {{ partial "header.html" . }}
2 |
3 | {{ .Content }}
4 |
5 |
11 |
12 |
13 | {{ partial "footer.html" . }}
14 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/index.html:
--------------------------------------------------------------------------------
1 | {{ partial "header.html" . }}
2 |
5 |
6 | {{if .Site.Home.Content }}
7 | {{.Site.Home.Content}}
8 | {{else}}
9 | {{if eq .Site.Language.Lang "fr"}}
10 | Personaliser la page d'accueil
11 |
12 | Le site fonctionne. Ne pas oublier de personaliser cette page avec votre propre contenu. 3 manières de faire :
13 |
14 |
15 | 1. Créer un fichier _index.md dans le dossier content et le remplir de Markdown
16 | 2. Créer un fichier index.html dans le dossier static et le remplir de code HTML
17 | 3. Configurer le serveur http pour rediriger automatiquement la homepage vers la page de votre choix dans le site
18 |
19 | {{else}}
20 | Customize your own home page
21 |
22 | The site is working. Don't forget to customize this homepage with your own. You typically have 3 choices :
23 |
24 |
25 | 1. Create an _index.md document in content folder and fill it with Markdown content
26 | 2. Create an index.html file in the static folder and fill the file with HTML content
27 | 3. Configure your server to automatically redirect home page to one your documentation page
28 |
29 | {{end}}
30 | {{ end }}
31 | {{ partial "footer.html" . }}
32 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/index.json:
--------------------------------------------------------------------------------
1 | [{{ range $index, $page := .Site.Pages }}
2 | {{- if ne $page.Type "json" -}}
3 | {{- if and $index (gt $index 0) -}},{{- end }}
4 | {
5 | "uri": "{{ $page.Permalink }}",
6 | "title": "{{ htmlEscape $page.Title}}",
7 | "tags": [{{ range $tindex, $tag := $page.Params.tags }}{{ if $tindex }}, {{ end }}"{{ $tag| htmlEscape }}"{{ end }}],
8 | "description": "{{ htmlEscape .Description}}",
9 | "content": {{$page.Plain | jsonify}}
10 | }
11 | {{- end -}}
12 | {{- end -}}]
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/custom-comments.html:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/custom-footer.html:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/custom-header.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/favicon.html:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/menu-footer.html:
--------------------------------------------------------------------------------
1 | Built with from Grav and Hugo
2 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/meta.html:
--------------------------------------------------------------------------------
1 |
2 | {{ with .Site.Params.author }} {{ end }}
3 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ $assetBusting := not .Site.Params.disableAssetsBusting }}
7 |
8 |
9 |
16 |
17 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/partials/toc.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | {{ .TableOfContents }}
4 |
5 |
6 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/attachments.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{with .Get "title"}}{{.}}{{else}}{{T "Attachments-label"}}{{end}}
5 |
6 | {{if eq .Page.File.BaseFileName "index"}}
7 | {{$.Scratch.Add "filesName" "files"}}
8 | {{else}}
9 | {{$.Scratch.Add "filesName" (printf "%s.files" .Page.File.BaseFileName)}}
10 | {{end}}
11 |
12 | {{ range (readDir (printf "./content/%s%s" .Page.File.Dir ($.Scratch.Get "filesName")) ) }}
13 | {{ $fileDir := replace $.Page.File.Dir "\\" "/" }}
14 | {{if ($.Get "pattern")}}
15 | {{if (findRE ($.Get "pattern") .Name)}}
16 |
17 |
18 | {{.Name}}
19 |
20 | ({{div .Size 1024 }} ko)
21 |
22 | {{end}}
23 | {{else}}
24 |
25 |
26 | {{.Name}}
27 |
28 | ({{div .Size 1024 }} ko)
29 |
30 | {{end}}
31 | {{end}}
32 |
33 | {{.Inner}}
34 |
35 |
36 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/button.html:
--------------------------------------------------------------------------------
1 |
2 | {{ $icon := .Get "icon" }}
3 | {{ $iconposition := .Get "icon-position" }}
4 | {{ if ($icon) }}
5 | {{ if or (not ($iconposition)) (eq $iconposition "left") }}
6 |
7 | {{ end }}
8 | {{ end }}
9 | {{ .Inner }}
10 | {{ if and ($icon) (eq $iconposition "right")}}
11 |
12 | {{ end }}
13 |
14 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/expand.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{$expandMessage := T "Expand-title"}}
7 | {{ if .IsNamedParams }}
8 | {{.Get "default" | default $expandMessage}}
9 | {{else}}
10 | {{.Get 0 | default $expandMessage}}
11 | {{end}}
12 |
13 |
14 |
15 |
16 | {{.Inner | safeHTML}}
17 |
18 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/mermaid.html:
--------------------------------------------------------------------------------
1 |
{{ safeHTML .Inner }}
2 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/notice.html:
--------------------------------------------------------------------------------
1 |
{{ .Inner }}
2 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/ref.html:
--------------------------------------------------------------------------------
1 | {{- if in (.Get 0) "/_index.md" -}}
2 | {{- $paths := (split (.Get 0) "_index.md") -}}
3 | {{- $pagepath := index $paths 0 -}}
4 | {{- $anchor := index $paths 1 -}}
5 | {{- with .Site.GetPage "section" (trim $pagepath "/") -}}
6 | {{- ( printf "%s%s" $pagepath $anchor ) | relLangURL -}}
7 | {{- end -}}
8 | {{- else -}}
9 | {{- with .Site.GetPage "section" (.Get 0) }}
10 | {{- .URL -}}
11 | {{- else -}}
12 | {{- .Get 0 | relref .Page -}}
13 | {{- end -}}
14 | {{- end -}}
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/relref.html:
--------------------------------------------------------------------------------
1 | {{- if in (.Get 0) "/_index.md" -}}
2 | {{- $paths := (split (.Get 0) "_index.md") -}}
3 | {{- $pagepath := index $paths 0 -}}
4 | {{- $anchor := index $paths 1 -}}
5 | {{- with .Site.GetPage "section" (trim $pagepath "/") -}}
6 | {{- ( printf "%s%s" $pagepath $anchor ) | relLangURL -}}
7 | {{- end -}}
8 | {{- else -}}
9 | {{- with .Site.GetPage "section" (.Get 0) }}
10 | {{- .URL -}}
11 | {{- else -}}
12 | {{- .Get 0 | relref .Page -}}
13 | {{- end -}}
14 | {{- end -}}
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/layouts/shortcodes/siteparam.html:
--------------------------------------------------------------------------------
1 | {{- $paramName := (.Get 0) -}}
2 | {{- $siteParams := .Site.Params -}}
3 | {{- with $paramName -}}
4 | {{- with $siteParams -}}
5 | {{- index . (lower $paramName) -}}
6 | {{- end -}}
7 | {{- end -}}
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/netlify.toml:
--------------------------------------------------------------------------------
1 | [build]
2 | publish = "exampleSite/public"
3 | command = "hugo -s exampleSite"
4 |
5 | [build.environment]
6 | HUGO_THEME = "repo"
7 | HUGO_THEMESDIR = "/opt/build"
8 | HUGO_VERSION = "0.50"
9 |
10 | [context.production.environment]
11 | HUGO_BASEURL = "https://learn.netlify.com/"
12 |
13 | [context.deploy-preview]
14 | command = "hugo -s exampleSite -b $DEPLOY_PRIME_URL"
15 |
16 | [context.deploy-preview.environment]
17 | HUGO_ENABLEGITINFO = "true"
18 |
19 | [context.branch-deplpy]
20 | command = "hugo -s exampleSite -b $DEPLOY_PRIME_URL"
21 |
22 | [context.branch-deploy.environment]
23 | HUGO_ENABLEGITINFO = "true"
24 |
25 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/css/auto-complete.css:
--------------------------------------------------------------------------------
1 | .autocomplete-suggestions {
2 | text-align: left;
3 | cursor: default;
4 | border: 1px solid #ccc;
5 | border-top: 0;
6 | background: #fff;
7 | box-shadow: -1px 1px 3px rgba(0,0,0,.1);
8 |
9 | /* core styles should not be changed */
10 | position: absolute;
11 | display: none;
12 | z-index: 9999;
13 | max-height: 254px;
14 | overflow: hidden;
15 | overflow-y: auto;
16 | box-sizing: border-box;
17 |
18 | }
19 | .autocomplete-suggestion {
20 | position: relative;
21 | cursor: pointer;
22 | padding: 7px;
23 | line-height: 23px;
24 | white-space: nowrap;
25 | overflow: hidden;
26 | text-overflow: ellipsis;
27 | color: #333;
28 | }
29 |
30 | .autocomplete-suggestion b {
31 | font-weight: normal;
32 | color: #1f8dd6;
33 | }
34 |
35 | .autocomplete-suggestion.selected {
36 | background: #333;
37 | color: #fff;
38 | }
39 |
40 | .autocomplete-suggestion:hover {
41 | background: #444;
42 | color: #fff;
43 | }
44 |
45 | .autocomplete-suggestion > .context {
46 | font-size: 12px;
47 | }
48 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/css/featherlight.min.css:
--------------------------------------------------------------------------------
1 | /**
2 | * Featherlight - ultra slim jQuery lightbox
3 | * Version 1.2.3 - http://noelboss.github.io/featherlight/
4 | *
5 | * Copyright 2015, Noël Raoul Bossart (http://www.noelboss.com)
6 | * MIT Licensed.
7 | **/
8 | @media all{.featherlight{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:2147483647;text-align:center;white-space:nowrap;cursor:pointer;background:#333;background:rgba(0,0,0,0)}.featherlight:last-of-type{background:rgba(0,0,0,.8)}.featherlight:before{content:'';display:inline-block;height:100%;vertical-align:middle;margin-right:-.25em}.featherlight .featherlight-content{position:relative;text-align:left;vertical-align:middle;display:inline-block;overflow:auto;padding:25px 25px 0;border-bottom:25px solid transparent;min-width:30%;margin-left:5%;margin-right:5%;max-height:95%;background:#fff;cursor:auto;white-space:normal}.featherlight .featherlight-inner{display:block}.featherlight .featherlight-close-icon{position:absolute;z-index:9999;top:0;right:0;line-height:25px;width:25px;cursor:pointer;text-align:center;font:Arial,sans-serif;background:#fff;background:rgba(255,255,255,.3);color:#000}.featherlight .featherlight-image{width:100%}.featherlight-iframe .featherlight-content{border-bottom:0;padding:0}.featherlight iframe{border:0}}@media only screen and (max-width:1024px){.featherlight .featherlight-content{margin-left:10px;margin-right:10px;max-height:98%;padding:10px 10px 0;border-bottom:10px solid transparent}}
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/css/hybrid-theme-purple.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Agate by Taufik Nurrohman
3 | * ----------------------------------------------------
4 | *
5 | * #ade5fc
6 | * #a2fca2
7 | * #c6b4f0
8 | * #d36363
9 | * #fcc28c
10 | * #fc9b9b
11 | * #ffa
12 | * #fff
13 | * #333
14 | * #62c8f3
15 | * #888
16 | *
17 | */
18 |
19 | .hljs {
20 | display: block;
21 | overflow-x: auto;
22 | padding: 0.5em;
23 | background: #333;
24 | color: white;
25 | }
26 |
27 | .hljs-name,
28 | .hljs-strong {
29 | font-weight: bold;
30 | }
31 |
32 | .hljs-code,
33 | .hljs-emphasis {
34 | font-style: italic;
35 | }
36 |
37 | .hljs-tag {
38 | color: #62c8f3;
39 | }
40 |
41 | .hljs-variable,
42 | .hljs-template-variable,
43 | .hljs-selector-id,
44 | .hljs-selector-class {
45 | color: #ade5fc;
46 | }
47 |
48 | .hljs-string,
49 | .hljs-bullet {
50 | color: #a2fca2;
51 | }
52 |
53 | .hljs-type,
54 | .hljs-title,
55 | .hljs-section,
56 | .hljs-attribute,
57 | .hljs-quote,
58 | .hljs-built_in,
59 | .hljs-builtin-name {
60 | color: #ffa;
61 | }
62 |
63 | .hljs-number,
64 | .hljs-symbol,
65 | .hljs-bullet {
66 | color: #d36363;
67 | }
68 |
69 | .hljs-keyword,
70 | .hljs-selector-tag,
71 | .hljs-literal {
72 | color: #fcc28c;
73 | }
74 |
75 | .hljs-comment,
76 | .hljs-deletion,
77 | .hljs-code {
78 | color: #888;
79 | }
80 |
81 | .hljs-regexp,
82 | .hljs-link {
83 | color: #c6b4f0;
84 | }
85 |
86 | .hljs-meta {
87 | color: #fc9b9b;
88 | }
89 |
90 | .hljs-deletion {
91 | background-color: #fc9b9b;
92 | color: #333;
93 | }
94 |
95 | .hljs-addition {
96 | background-color: #a2fca2;
97 | color: #333;
98 | }
99 |
100 | .hljs a {
101 | color: inherit;
102 | }
103 |
104 | .hljs a:focus,
105 | .hljs a:hover {
106 | color: inherit;
107 | text-decoration: underline;
108 | }
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/css/hybrid.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Agate by Taufik Nurrohman
3 | * ----------------------------------------------------
4 | *
5 | * #ade5fc
6 | * #a2fca2
7 | * #c6b4f0
8 | * #d36363
9 | * #fcc28c
10 | * #fc9b9b
11 | * #ffa
12 | * #fff
13 | * #333
14 | * #62c8f3
15 | * #888
16 | *
17 | */
18 |
19 | .hljs {
20 | display: block;
21 | overflow-x: auto;
22 | /* padding: 0.5em; */
23 | /* background: #333; */
24 | background: #1d1f21;
25 | color: white;
26 | }
27 |
28 | .hljs-name,
29 | .hljs-strong {
30 | font-weight: bold;
31 | }
32 |
33 | .hljs-code,
34 | .hljs-emphasis {
35 | font-style: italic;
36 | }
37 |
38 | .hljs-tag {
39 | color: #62c8f3;
40 | }
41 |
42 | .hljs-variable,
43 | .hljs-template-variable,
44 | .hljs-selector-id,
45 | .hljs-selector-class {
46 | color: #ade5fc;
47 | }
48 |
49 | .hljs-string,
50 | .hljs-bullet {
51 | color: #a2fca2;
52 | }
53 |
54 | .hljs-type,
55 | .hljs-title,
56 | .hljs-section,
57 | .hljs-attribute,
58 | .hljs-quote,
59 | .hljs-built_in,
60 | .hljs-builtin-name {
61 | color: #ffa;
62 | }
63 |
64 | .hljs-number,
65 | .hljs-symbol,
66 | .hljs-bullet {
67 | color: #d36363;
68 | }
69 |
70 | .hljs-keyword,
71 | .hljs-selector-tag,
72 | .hljs-literal {
73 | color: #fcc28c;
74 | }
75 |
76 | .hljs-comment,
77 | .hljs-deletion,
78 | .hljs-code {
79 | color: rgb(186, 173, 219);
80 | }
81 |
82 | .hljs-regexp,
83 | .hljs-link {
84 | color: #c6b4f0;
85 | }
86 |
87 | .hljs-meta {
88 | color: #fc9b9b;
89 | }
90 |
91 | .hljs-deletion {
92 | background-color: #fc9b9b;
93 | color: #333;
94 | }
95 |
96 | .hljs-addition {
97 | background-color: #a2fca2;
98 | color: #333;
99 | }
100 |
101 | .hljs a {
102 | color: inherit;
103 | }
104 |
105 | .hljs a:focus,
106 | .hljs a:hover {
107 | color: inherit;
108 | text-decoration: underline;
109 | }
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Inconsolata.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Inconsolata.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Inconsolata.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Inconsolata.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Inconsolata.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Inconsolata.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-Normal-webfont.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_200.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_300.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/fonts/Work_Sans_500.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/images/clippy.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/images/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/images/favicon.png
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/images/gopher-404.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/images/gopher-404.jpg
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/js/hugo-learn.js:
--------------------------------------------------------------------------------
1 | // Get Parameters from some url
2 | var getUrlParameter = function getUrlParameter(sPageURL) {
3 | var url = sPageURL.split('?');
4 | var obj = {};
5 | if (url.length == 2) {
6 | var sURLVariables = url[1].split('&'),
7 | sParameterName,
8 | i;
9 | for (i = 0; i < sURLVariables.length; i++) {
10 | sParameterName = sURLVariables[i].split('=');
11 | obj[sParameterName[0]] = sParameterName[1];
12 | }
13 | return obj;
14 | } else {
15 | return undefined;
16 | }
17 | };
18 |
19 | // Execute actions on images generated from Markdown pages
20 | var images = $("div#body-inner img").not(".inline");
21 | // Wrap image inside a featherlight (to get a full size view in a popup)
22 | images.wrap(function(){
23 | var image =$(this);
24 | if (!image.parent("a").length) {
25 | return " ";
26 | }
27 | });
28 |
29 | // Change styles, depending on parameters set to the image
30 | images.each(function(index){
31 | var image = $(this)
32 | var o = getUrlParameter(image[0].src);
33 | if (typeof o !== "undefined") {
34 | var h = o["height"];
35 | var w = o["width"];
36 | var c = o["classes"];
37 | image.css("width", function() {
38 | if (typeof w !== "undefined") {
39 | return w;
40 | } else {
41 | return "auto";
42 | }
43 | });
44 | image.css("height", function() {
45 | if (typeof h !== "undefined") {
46 | return h;
47 | } else {
48 | return "auto";
49 | }
50 | });
51 | if (typeof c !== "undefined") {
52 | var classes = c.split(',');
53 | for (i = 0; i < classes.length; i++) {
54 | image.addClass(classes[i]);
55 | }
56 | }
57 | }
58 | });
59 |
60 | // Stick the top to the top of the screen when scrolling
61 | $(document).ready(function(){
62 | $("#top-bar").sticky({topSpacing:0, zIndex: 1000});
63 | });
64 |
65 |
66 | jQuery(document).ready(function() {
67 | // Add link button for every
68 | var text, clip = new Clipboard('.anchor');
69 | $("h1~h2,h1~h3,h1~h4,h1~h5,h1~h6").append(function(index, html){
70 | var element = $(this);
71 | var url = encodeURI(document.location.origin + document.location.pathname);
72 | var link = url + "#"+element[0].id;
73 | return " " +
74 | " " +
75 | " "
76 | ;
77 | });
78 |
79 | $(".anchor").on('mouseleave', function(e) {
80 | $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w');
81 | });
82 |
83 | clip.on('success', function(e) {
84 | e.clearSelection();
85 | $(e.trigger).attr('aria-label', 'Link copied to clipboard!').addClass('tooltipped tooltipped-s');
86 | });
87 |
88 | });
89 |
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-brands-400.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-regular-400.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.eot
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.ttf
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.woff
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/nnja/python/e5e912339b50a84ee31f5cadb0f70ef45c9abb15/website/themes/nnja-theme-learn/static/webfonts/fa-solid-900.woff2
--------------------------------------------------------------------------------
/website/themes/nnja-theme-learn/theme.toml:
--------------------------------------------------------------------------------
1 | # theme.toml template for a Hugo theme
2 | # See https://github.com/spf13/hugoThemes#themetoml for an example
3 |
4 | name = "Learn"
5 | license = "MIT"
6 | licenselink = "https://github.com/matcornic/hugo-theme-learn/blob/master/LICENSE.md"
7 | description = "Documentation theme for Hugo, based on Grav Learn theme"
8 | homepage = "https://github.com/matcornic/hugo-theme-learn/"
9 | repo = "https://github.com/matcornic/hugo-theme-learn"
10 | tags = ["documentation", "grav", "learn", "doc", "search"]
11 | features = ["documentation", "menu", "nested sections", "search", "mermaid"]
12 | min_version = 0.25
13 |
14 | [author]
15 | name = "Mathieu Cornic"
16 | homepage = "https://matcornic.github.io/"
17 |
18 | [original]
19 | name = "Grav Learn"
20 | homepage = "https://learn.getgrav.org/"
21 | repo = "https://github.com/getgrav/grav-learn"
22 |
--------------------------------------------------------------------------------