From 895c5422a98fe05499a97233cb8125bdf12b850a Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Tue, 18 Apr 2023 09:48:17 +0300 Subject: [PATCH 01/30] Get rid of unneeded stuff --- .travis.yml | 17 -------- tox.ini | 15 ------- utils/post_save_hook.py | 97 ----------------------------------------- 3 files changed, 129 deletions(-) delete mode 100644 .travis.yml delete mode 100644 tox.ini delete mode 100644 utils/post_save_hook.py diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9b5710e..0000000 --- a/.travis.yml +++ /dev/null @@ -1,17 +0,0 @@ -os: linux -dist: focal -language: python - -jobs: - include: - - python: 3.5 - env: TOXENV=py35 - - python: 3.6 - env: TOXENV=py36 - - python: 3.7 - env: TOXENV=py37 - - python: 3.8 - env: TOXENV=py38 - -install: pip install jupyter nbval pytest tox -script: tox diff --git a/tox.ini b/tox.ini deleted file mode 100644 index c697cfc..0000000 --- a/tox.ini +++ /dev/null @@ -1,15 +0,0 @@ -[tox] -skipsdist = True -envlist = py35, - py36, - py37, - py38 -skip_missing_interpreters = true - -[testenv] -deps = - pytest - nbval - jupyter -commands = - pytest --nbval notebooks diff --git a/utils/post_save_hook.py b/utils/post_save_hook.py deleted file mode 100644 index daf2b6f..0000000 --- a/utils/post_save_hook.py +++ /dev/null @@ -1,97 +0,0 @@ -""" -Jupyter post_save_hook script for generating .py/.html files automatically when .ipynb file is saved. - -Add the content to your jupyter_notebook_config.py. The location is usually $HOME/.jupyter/jupyter_notebook_config.py. -If you don't have one yet, you can generate the file: jupyter notebook --generate-config -""" - -import json -import os -from subprocess import check_call - -SAVE_PY = False # Save .py files (location is /py/) -SAVE_HTML = True # Save .html files (location is /html/) - -# Run notebook before saving py/html. Note: this won't affect to the state of the .ipynb file. -RUN_NB_BEFORE_SAVE = True - -# Skip saving of files which name contains of the following -DONT_SAVE = {'exercise', 'copy', 'untitled'} - -# Add beatufil "Toggle output" button at the top of html page -USE_TOGGLE_BTN_IN_HTML = True - -TOGGLE_OUTPUT_BTN = { - "cell_type": - "raw", - "metadata": {}, - "source": [ - "\n", "\n", - "
\n", - " \n", "\n", "
" - ] -} - - -def _run_cmd(cmd, cwd=None): - check_call(cmd.split(), cwd=cwd) - - -def post_save(model, os_path, contents_manager): - if model['type'] != 'notebook' or not (SAVE_PY or SAVE_HTML): - return - - dir_, fname = os.path.split(os_path) - - for word in DONT_SAVE: - if word.lower() in fname.lower(): - return - - source, tmp_name = fname, None - out_file_base, _ = os.path.splitext(fname) - - if RUN_NB_BEFORE_SAVE: - tmp_name = 'tmp_{}'.format(fname) - cmd = 'jupyter nbconvert --to notebook --execute --ExecutePreprocessor.timeout=30 --output {} {}'.format( - tmp_name, os_path) - _run_cmd(cmd, cwd=dir_) - source = tmp_name - - if SAVE_PY: - out_dir_py = os.path.join(os.path.dirname(dir_), 'py') - os.makedirs(out_dir_py, exist_ok=True) - cmd = 'jupyter nbconvert --to python --output-dir {} --output {}.py {}'.format( - out_dir_py, out_file_base, source) - _run_cmd(cmd, cwd=dir_) - - if SAVE_HTML: - if USE_TOGGLE_BTN_IN_HTML and RUN_NB_BEFORE_SAVE: - with open(os.path.join(dir_, source), 'r+') as tmp_source: - content = json.loads(tmp_source.read()) - content['cells'] = [TOGGLE_OUTPUT_BTN] + content.get( - 'cells', []) - tmp_source.seek(0) - tmp_source.write(json.dumps(content)) - tmp_source.truncate() - - out_dir_html = os.path.join(os.path.dirname(dir_), 'html') - os.makedirs(out_dir_html, exist_ok=True) - cmd = 'jupyter nbconvert --to html --output-dir {} --output {}.html {}'.format( - out_dir_html, out_file_base, source) - _run_cmd(cmd, cwd=dir_) - - if tmp_name: - tmp_file = os.path.join(dir_, tmp_name) - if os.path.exists(tmp_file): - os.remove(tmp_file) - -c.FileContentsManager.post_save_hook = post_save \ No newline at end of file From b62bc6a84fa96ec4a1026f7ab25e1f76f81a6b00 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Tue, 18 Apr 2023 09:48:25 +0300 Subject: [PATCH 02/30] Update year --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index a798ba0..c77d8c1 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2018 jerry-git +Copyright (c) 2023 jerry-git Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From 3038adda0ff3b39bbc5e291ac4f4bfa89f76fb3f Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Tue, 18 Apr 2023 09:48:43 +0300 Subject: [PATCH 03/30] Add pre-commit config --- .pre-commit-config.yaml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .pre-commit-config.yaml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..a2296f5 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,13 @@ +repos: + - repo: local + hooks: + - id: clear-nb-output + name: clear-nb-output + files: \.ipynb$ + language: system + entry: jupyter nbconvert --ClearOutputPreprocessor.enabled=True --inplace + - id: black + name: black + entry: black + language: system + files: \.(py|ipynb)$ From 906ba3626cce7e0cd768941d9b78401c7c14a473 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Tue, 18 Apr 2023 09:52:58 +0300 Subject: [PATCH 04/30] Add requirements file for dev deps --- dev-requirements.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 dev-requirements.txt diff --git a/dev-requirements.txt b/dev-requirements.txt new file mode 100644 index 0000000..e3f4c05 --- /dev/null +++ b/dev-requirements.txt @@ -0,0 +1,5 @@ +black[jupyter] +jupyter +nbval +pre-commit +pytest From c790fee8bf2697706acfc2fb159cb7101d667f54 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Tue, 18 Apr 2023 09:53:20 +0300 Subject: [PATCH 05/30] Add script for converting notebooks to html --- scripts/notebook_to_html.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 scripts/notebook_to_html.py diff --git a/scripts/notebook_to_html.py b/scripts/notebook_to_html.py new file mode 100644 index 0000000..d39f83a --- /dev/null +++ b/scripts/notebook_to_html.py @@ -0,0 +1,36 @@ +from pathlib import Path +import subprocess +import sys + + +def main(): + path = sys.argv[1] + if path.strip().lower() == "all": + convert_all_notebooks_to_html() + else: + convert_notebook_to_html(path) + + +def convert_all_notebooks_to_html(): + notebook_dir = Path(__file__).parent.parent / "notebooks" + for directory in ( + notebook_dir / "beginner" / "notebooks", + notebook_dir / "intermediate" / "notebooks", + ): + for notebook_path in directory.glob("*.ipynb"): + convert_notebook_to_html(notebook_path) + + +def convert_notebook_to_html(notebook_path): + path = Path(notebook_path) + if not path.exists(): + raise SystemExit(f"Invalid path {path}") + + output_dir = path.parent.parent / "html" + + cmd = f"jupyter nbconvert --to html --execute --ExecutePreprocessor.timeout=30 --output-dir {output_dir} {path.absolute()}" + subprocess.check_call(cmd.split()) + + +if __name__ == "__main__": + main() From 3c0ef8ac7d79d3680ba44845a24aee812e6871d4 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 19 Apr 2023 09:53:39 +0300 Subject: [PATCH 06/30] Ignore tmp.txt --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f9071de..bd511d4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ .pytest_cache* .tox* *pycache* -sync-*.sh \ No newline at end of file +sync-*.sh +tmp.txt From f47a4239c5bf969ba0948d7313f77a381834b646 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 19 Apr 2023 10:01:49 +0300 Subject: [PATCH 07/30] Ignore my_log.txt --- .gitignore | 1 + notebooks/beginner/notebooks/my_log.txt | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) delete mode 100644 notebooks/beginner/notebooks/my_log.txt diff --git a/.gitignore b/.gitignore index bd511d4..b7fdea9 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ *pycache* sync-*.sh tmp.txt +my_log.txt diff --git a/notebooks/beginner/notebooks/my_log.txt b/notebooks/beginner/notebooks/my_log.txt deleted file mode 100644 index 1a87c50..0000000 --- a/notebooks/beginner/notebooks/my_log.txt +++ /dev/null @@ -1,2 +0,0 @@ -2018-09-21 23:17:54,486 | MyFileLogger | WARNING | Oops something is going to happen -2018-09-21 23:17:54,486 | MyFileLogger | ERROR | John Doe visits our place From fb4b0e6be9d266b9f63c4839fa4bf9aba36edc5b Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 19 Apr 2023 10:22:59 +0300 Subject: [PATCH 08/30] Add numbering and regenerate html Also fixed some ipytest things --- ...ercise.ipynb => 01_strings_exercise.ipynb} | 28 +- ...ercise.ipynb => 02_numbers_exercise.ipynb} | 3 +- ...e.ipynb => 03_conditionals_exercise.ipynb} | 14 +- ...exercise.ipynb => 04_lists_exercise.ipynb} | 21 +- ...e.ipynb => 05_dictionaries_exercise.ipynb} | 35 +- ...cise.ipynb => 06_for_loops_exercise.ipynb} | 17 +- ...cise.ipynb => 07_functions_exercise.ipynb} | 18 +- ...rcise.ipynb => 08_testing1_exercise.ipynb} | 5 +- ...xercise.ipynb => 09_recap1_exercise.ipynb} | 34 +- ...ercise.ipynb => 10_file_io_exercise.ipynb} | 14 +- ...ercise.ipynb => 11_classes_exercise.ipynb} | 16 +- ...ise.ipynb => 12_exceptions_exercise.ipynb} | 16 +- ...cise.ipynb => 14_debugging_exercise.ipynb} | 10 +- ...rcise.ipynb => 15_std_lib1_exercise.ipynb} | 9 +- ...rcise.ipynb => 16_testing2_exercise.ipynb} | 7 +- ...xercise.ipynb => 19_recap2_exercise.ipynb} | 53 +- notebooks/beginner/html/01_strings.html | 16216 +++++++++++++++ notebooks/beginner/html/02_numbers.html | 15613 +++++++++++++++ notebooks/beginner/html/03_conditionals.html | 15893 +++++++++++++++ notebooks/beginner/html/04_lists.html | 15917 +++++++++++++++ notebooks/beginner/html/05_dictionaries.html | 15843 +++++++++++++++ notebooks/beginner/html/06_for_loops.html | 15577 +++++++++++++++ notebooks/beginner/html/07_functions.html | 15675 +++++++++++++++ notebooks/beginner/html/08_testing1.html | 15376 +++++++++++++++ notebooks/beginner/html/10_file_io.html | 15414 +++++++++++++++ notebooks/beginner/html/11_classes.html | 15744 +++++++++++++++ notebooks/beginner/html/12_exceptions.html | 15380 +++++++++++++++ .../html/13_modules_and_packages.html | 15231 ++++++++++++++ notebooks/beginner/html/14_debugging.html | 15247 ++++++++++++++ notebooks/beginner/html/15_std_lib.html | 15973 +++++++++++++++ notebooks/beginner/html/16_testing2.html | 15487 +++++++++++++++ notebooks/beginner/html/17_venv.html | 15205 ++++++++++++++ .../beginner/html/18_project_structure.html | 15251 ++++++++++++++ notebooks/beginner/html/classes.html | 12335 ------------ notebooks/beginner/html/conditionals.html | 12397 ------------ notebooks/beginner/html/debugging.html | 11919 ----------- notebooks/beginner/html/dictionaries.html | 12410 ------------ notebooks/beginner/html/exceptions.html | 12025 ----------- notebooks/beginner/html/file_io.html | 12053 ------------ notebooks/beginner/html/for_loops.html | 12192 ------------ notebooks/beginner/html/functions.html | 12274 ------------ notebooks/beginner/html/lists.html | 12472 ------------ .../beginner/html/modules_and_packages.html | 11903 ----------- notebooks/beginner/html/numbers.html | 12216 ------------ .../beginner/html/project_structure.html | 11925 ----------- notebooks/beginner/html/std_lib.html | 12517 ------------ notebooks/beginner/html/strings.html | 12711 ------------ notebooks/beginner/html/testing1.html | 12007 ----------- notebooks/beginner/html/testing2.html | 12097 ------------ notebooks/beginner/html/venv.html | 11874 ----------- .../{strings.ipynb => 01_strings.ipynb} | 70 +- .../{numbers.ipynb => 02_numbers.ipynb} | 40 +- ...nditionals.ipynb => 03_conditionals.ipynb} | 115 +- .../notebooks/{lists.ipynb => 04_lists.ipynb} | 60 +- ...ctionaries.ipynb => 05_dictionaries.ipynb} | 92 +- .../{for_loops.ipynb => 06_for_loops.ipynb} | 10 +- .../{functions.ipynb => 07_functions.ipynb} | 48 +- .../{testing1.ipynb => 08_testing1.ipynb} | 14 +- .../{file_io.ipynb => 10_file_io.ipynb} | 34 +- .../{classes.ipynb => 11_classes.ipynb} | 90 +- .../{exceptions.ipynb => 12_exceptions.ipynb} | 38 +- ...es.ipynb => 13_modules_and_packages.ipynb} | 0 .../{debugging.ipynb => 14_debugging.ipynb} | 8 +- .../{std_lib.ipynb => 15_std_lib.ipynb} | 122 +- .../{testing2.ipynb => 16_testing2.ipynb} | 42 +- .../notebooks/{venv.ipynb => 17_venv.ipynb} | 0 ...cture.ipynb => 18_project_structure.ipynb} | 4 +- ...rcise.ipynb => 01_std_lib2_exercise.ipynb} | 56 +- ...ynb => 05_idiomatic_python_exercise.ipynb} | 66 +- .../intermediate/html/01_best_practices.html | 15945 +++++++++++++++ .../intermediate/html/01_idiomatic_loops.html | 16013 +++++++++++++++ .../intermediate/html/01_pytest_fixtures.html | 15902 +++++++++++++++ notebooks/intermediate/html/01_std_lib2.html | 15788 +++++++++++++++ .../intermediate/html/02_idiomatic_dicts.html | 15879 +++++++++++++++ .../intermediate/html/03_idiomatic_misc1.html | 16410 ++++++++++++++++ .../intermediate/html/04_idiomatic_misc2.html | 16268 +++++++++++++++ .../intermediate/html/best_practices.html | 12473 ------------ .../intermediate/html/idiomatic_dicts.html | 12431 ------------ .../intermediate/html/idiomatic_loops.html | 12544 ------------ .../intermediate/html/idiomatic_misc1.html | 12875 ------------ .../intermediate/html/idiomatic_misc2.html | 12761 ------------ .../intermediate/html/pytest_fixtures.html | 12542 ------------ notebooks/intermediate/html/std_lib2.html | 12366 ------------ ...ractices.ipynb => 01_best_practices.ipynb} | 0 ...c_loops.ipynb => 01_idiomatic_loops.ipynb} | 20 +- ...ixtures.ipynb => 01_pytest_fixtures.ipynb} | 95 +- .../{std_lib2.ipynb => 01_std_lib2.ipynb} | 89 +- ...c_dicts.ipynb => 02_idiomatic_dicts.ipynb} | 40 +- ...c_misc1.ipynb => 03_idiomatic_misc1.ipynb} | 107 +- ...c_misc2.ipynb => 04_idiomatic_misc2.ipynb} | 121 +- 90 files changed, 378126 insertions(+), 296121 deletions(-) rename notebooks/beginner/exercises/{strings_exercise.ipynb => 01_strings_exercise.ipynb} (82%) rename notebooks/beginner/exercises/{numbers_exercise.ipynb => 02_numbers_exercise.ipynb} (97%) rename notebooks/beginner/exercises/{conditionals_exercise.ipynb => 03_conditionals_exercise.ipynb} (82%) rename notebooks/beginner/exercises/{lists_exercise.ipynb => 04_lists_exercise.ipynb} (83%) rename notebooks/beginner/exercises/{dictionaries_exercise.ipynb => 05_dictionaries_exercise.ipynb} (71%) rename notebooks/beginner/exercises/{for_loops_exercise.ipynb => 06_for_loops_exercise.ipynb} (85%) rename notebooks/beginner/exercises/{functions_exercise.ipynb => 07_functions_exercise.ipynb} (83%) rename notebooks/beginner/exercises/{testing1_exercise.ipynb => 08_testing1_exercise.ipynb} (91%) rename notebooks/beginner/exercises/{recap1_exercise.ipynb => 09_recap1_exercise.ipynb} (79%) rename notebooks/beginner/exercises/{file_io_exercise.ipynb => 10_file_io_exercise.ipynb} (85%) rename notebooks/beginner/exercises/{classes_exercise.ipynb => 11_classes_exercise.ipynb} (90%) rename notebooks/beginner/exercises/{exceptions_exercise.ipynb => 12_exceptions_exercise.ipynb} (88%) rename notebooks/beginner/exercises/{debugging_exercise.ipynb => 14_debugging_exercise.ipynb} (87%) rename notebooks/beginner/exercises/{std_lib1_exercise.ipynb => 15_std_lib1_exercise.ipynb} (90%) rename notebooks/beginner/exercises/{testing2_exercise.ipynb => 16_testing2_exercise.ipynb} (96%) rename notebooks/beginner/exercises/{recap2_exercise.ipynb => 19_recap2_exercise.ipynb} (80%) create mode 100644 notebooks/beginner/html/01_strings.html create mode 100644 notebooks/beginner/html/02_numbers.html create mode 100644 notebooks/beginner/html/03_conditionals.html create mode 100644 notebooks/beginner/html/04_lists.html create mode 100644 notebooks/beginner/html/05_dictionaries.html create mode 100644 notebooks/beginner/html/06_for_loops.html create mode 100644 notebooks/beginner/html/07_functions.html create mode 100644 notebooks/beginner/html/08_testing1.html create mode 100644 notebooks/beginner/html/10_file_io.html create mode 100644 notebooks/beginner/html/11_classes.html create mode 100644 notebooks/beginner/html/12_exceptions.html create mode 100644 notebooks/beginner/html/13_modules_and_packages.html create mode 100644 notebooks/beginner/html/14_debugging.html create mode 100644 notebooks/beginner/html/15_std_lib.html create mode 100644 notebooks/beginner/html/16_testing2.html create mode 100644 notebooks/beginner/html/17_venv.html create mode 100644 notebooks/beginner/html/18_project_structure.html delete mode 100644 notebooks/beginner/html/classes.html delete mode 100644 notebooks/beginner/html/conditionals.html delete mode 100644 notebooks/beginner/html/debugging.html delete mode 100644 notebooks/beginner/html/dictionaries.html delete mode 100644 notebooks/beginner/html/exceptions.html delete mode 100644 notebooks/beginner/html/file_io.html delete mode 100644 notebooks/beginner/html/for_loops.html delete mode 100644 notebooks/beginner/html/functions.html delete mode 100644 notebooks/beginner/html/lists.html delete mode 100644 notebooks/beginner/html/modules_and_packages.html delete mode 100644 notebooks/beginner/html/numbers.html delete mode 100644 notebooks/beginner/html/project_structure.html delete mode 100644 notebooks/beginner/html/std_lib.html delete mode 100644 notebooks/beginner/html/strings.html delete mode 100644 notebooks/beginner/html/testing1.html delete mode 100644 notebooks/beginner/html/testing2.html delete mode 100644 notebooks/beginner/html/venv.html rename notebooks/beginner/notebooks/{strings.ipynb => 01_strings.ipynb} (75%) rename notebooks/beginner/notebooks/{numbers.ipynb => 02_numbers.ipynb} (82%) rename notebooks/beginner/notebooks/{conditionals.ipynb => 03_conditionals.ipynb} (58%) rename notebooks/beginner/notebooks/{lists.ipynb => 04_lists.ipynb} (75%) rename notebooks/beginner/notebooks/{dictionaries.ipynb => 05_dictionaries.ipynb} (66%) rename notebooks/beginner/notebooks/{for_loops.ipynb => 06_for_loops.ipynb} (91%) rename notebooks/beginner/notebooks/{functions.ipynb => 07_functions.ipynb} (86%) rename notebooks/beginner/notebooks/{testing1.ipynb => 08_testing1.ipynb} (95%) rename notebooks/beginner/notebooks/{file_io.ipynb => 10_file_io.ipynb} (76%) rename notebooks/beginner/notebooks/{classes.ipynb => 11_classes.ipynb} (82%) rename notebooks/beginner/notebooks/{exceptions.ipynb => 12_exceptions.ipynb} (82%) rename notebooks/beginner/notebooks/{modules_and_packages.ipynb => 13_modules_and_packages.ipynb} (100%) rename notebooks/beginner/notebooks/{debugging.ipynb => 14_debugging.ipynb} (95%) rename notebooks/beginner/notebooks/{std_lib.ipynb => 15_std_lib.ipynb} (70%) rename notebooks/beginner/notebooks/{testing2.ipynb => 16_testing2.ipynb} (88%) rename notebooks/beginner/notebooks/{venv.ipynb => 17_venv.ipynb} (100%) rename notebooks/beginner/notebooks/{project_structure.ipynb => 18_project_structure.ipynb} (96%) rename notebooks/intermediate/exercises/{std_lib2_exercise.ipynb => 01_std_lib2_exercise.ipynb} (82%) rename notebooks/intermediate/exercises/{idiomatic_python_exercise.ipynb => 05_idiomatic_python_exercise.ipynb} (87%) create mode 100644 notebooks/intermediate/html/01_best_practices.html create mode 100644 notebooks/intermediate/html/01_idiomatic_loops.html create mode 100644 notebooks/intermediate/html/01_pytest_fixtures.html create mode 100644 notebooks/intermediate/html/01_std_lib2.html create mode 100644 notebooks/intermediate/html/02_idiomatic_dicts.html create mode 100644 notebooks/intermediate/html/03_idiomatic_misc1.html create mode 100644 notebooks/intermediate/html/04_idiomatic_misc2.html delete mode 100644 notebooks/intermediate/html/best_practices.html delete mode 100644 notebooks/intermediate/html/idiomatic_dicts.html delete mode 100644 notebooks/intermediate/html/idiomatic_loops.html delete mode 100644 notebooks/intermediate/html/idiomatic_misc1.html delete mode 100644 notebooks/intermediate/html/idiomatic_misc2.html delete mode 100644 notebooks/intermediate/html/pytest_fixtures.html delete mode 100644 notebooks/intermediate/html/std_lib2.html rename notebooks/intermediate/notebooks/{best_practices.ipynb => 01_best_practices.ipynb} (100%) rename notebooks/intermediate/notebooks/{idiomatic_loops.ipynb => 01_idiomatic_loops.ipynb} (94%) rename notebooks/intermediate/notebooks/{pytest_fixtures.ipynb => 01_pytest_fixtures.ipynb} (82%) rename notebooks/intermediate/notebooks/{std_lib2.ipynb => 01_std_lib2.ipynb} (79%) rename notebooks/intermediate/notebooks/{idiomatic_dicts.ipynb => 02_idiomatic_dicts.ipynb} (87%) rename notebooks/intermediate/notebooks/{idiomatic_misc1.ipynb => 03_idiomatic_misc1.ipynb} (82%) rename notebooks/intermediate/notebooks/{idiomatic_misc2.ipynb => 04_idiomatic_misc2.ipynb} (81%) diff --git a/notebooks/beginner/exercises/strings_exercise.ipynb b/notebooks/beginner/exercises/01_strings_exercise.ipynb similarity index 82% rename from notebooks/beginner/exercises/strings_exercise.ipynb rename to notebooks/beginner/exercises/01_strings_exercise.ipynb index 38aee8b..66a97be 100644 --- a/notebooks/beginner/exercises/strings_exercise.ipynb +++ b/notebooks/beginner/exercises/01_strings_exercise.ipynb @@ -14,7 +14,7 @@ "metadata": {}, "outputs": [], "source": [ - "original = ' Python strings are COOL! '\n", + "original = \" Python strings are COOL! \"\n", "lower_cased = original._____\n", "stripped = ____.strip()\n", "stripped_lower_cased = original._____._____" @@ -35,9 +35,9 @@ }, "outputs": [], "source": [ - "assert lower_cased == ' python strings are cool! '\n", - "assert stripped == 'Python strings are COOL!'\n", - "assert stripped_lower_cased == 'python strings are cool!'" + "assert lower_cased == \" python strings are cool! \"\n", + "assert stripped == \"Python strings are COOL!\"\n", + "assert stripped_lower_cased == \"python strings are cool!\"" ] }, { @@ -56,7 +56,7 @@ }, "outputs": [], "source": [ - "ugly = ' tiTle of MY new Book\\n\\n'" + "ugly = \" tiTle of MY new Book\\n\\n\"" ] }, { @@ -66,7 +66,7 @@ "outputs": [], "source": [ "# Your implementation:\n", - "pretty = 'TODO'" + "pretty = \"TODO\"" ] }, { @@ -84,8 +84,8 @@ }, "outputs": [], "source": [ - "print('pretty: {}'.format(pretty))\n", - "assert pretty == 'Title Of My New Book'" + "print(\"pretty: {}\".format(pretty))\n", + "assert pretty == \"Title Of My New Book\"" ] }, { @@ -104,9 +104,9 @@ }, "outputs": [], "source": [ - "verb = 'is'\n", - "language = 'Python'\n", - "punctuation = '!'" + "verb = \"is\"\n", + "language = \"Python\"\n", + "punctuation = \"!\"" ] }, { @@ -116,7 +116,7 @@ "outputs": [], "source": [ "# Your implementation:\n", - "sentence = 'TODO'" + "sentence = \"TODO\"" ] }, { @@ -127,8 +127,8 @@ }, "outputs": [], "source": [ - "print('sentence: {}'.format(sentence))\n", - "assert sentence == 'Learning Python is fun!'" + "print(\"sentence: {}\".format(sentence))\n", + "assert sentence == \"Learning Python is fun!\"" ] } ], diff --git a/notebooks/beginner/exercises/numbers_exercise.ipynb b/notebooks/beginner/exercises/02_numbers_exercise.ipynb similarity index 97% rename from notebooks/beginner/exercises/numbers_exercise.ipynb rename to notebooks/beginner/exercises/02_numbers_exercise.ipynb index 9b25a95..262a438 100644 --- a/notebooks/beginner/exercises/numbers_exercise.ipynb +++ b/notebooks/beginner/exercises/02_numbers_exercise.ipynb @@ -43,7 +43,6 @@ }, "outputs": [], "source": [ - "\n", "assert result == 50" ] }, @@ -57,7 +56,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ diff --git a/notebooks/beginner/exercises/conditionals_exercise.ipynb b/notebooks/beginner/exercises/03_conditionals_exercise.ipynb similarity index 82% rename from notebooks/beginner/exercises/conditionals_exercise.ipynb rename to notebooks/beginner/exercises/03_conditionals_exercise.ipynb index e0e045c..061c2c1 100644 --- a/notebooks/beginner/exercises/conditionals_exercise.ipynb +++ b/notebooks/beginner/exercises/03_conditionals_exercise.ipynb @@ -16,7 +16,7 @@ }, "outputs": [], "source": [ - "name = 'John Doe'" + "name = \"John Doe\"" ] }, { @@ -27,19 +27,19 @@ "source": [ "if ____:\n", " print('Name \"{}\" is more than 20 chars long'.format(name))\n", - " length_description = 'long'\n", + " length_description = \"long\"\n", "elif ____:\n", " print('Name \"{}\" is more than 15 chars long'.format(name))\n", - " length_description = 'semi long'\n", + " length_description = \"semi long\"\n", "elif ____:\n", " print('Name \"{}\" is more than 10 chars long'.format(name))\n", - " length_description = 'semi long'\n", + " length_description = \"semi long\"\n", "elif ____:\n", " print('Name \"{}\" is 8, 9 or 10 chars long'.format(name))\n", - " length_description = 'semi short'\n", + " length_description = \"semi short\"\n", "else:\n", " print('Name \"{}\" is a short name'.format(name))\n", - " length_description = 'short'" + " length_description = \"short\"" ] }, { @@ -50,7 +50,7 @@ }, "outputs": [], "source": [ - "assert length_description == 'semi short'" + "assert length_description == \"semi short\"" ] } ], diff --git a/notebooks/beginner/exercises/lists_exercise.ipynb b/notebooks/beginner/exercises/04_lists_exercise.ipynb similarity index 83% rename from notebooks/beginner/exercises/lists_exercise.ipynb rename to notebooks/beginner/exercises/04_lists_exercise.ipynb index 9c7645b..ea284b6 100644 --- a/notebooks/beginner/exercises/lists_exercise.ipynb +++ b/notebooks/beginner/exercises/04_lists_exercise.ipynb @@ -18,15 +18,15 @@ "my_list = ____\n", "\n", "# Let's add some values\n", - "my_list.____('Python')\n", - "my_list.____('is ok')\n", - "my_list.____('sometimes')\n", + "my_list.____(\"Python\")\n", + "my_list.____(\"is ok\")\n", + "my_list.____(\"sometimes\")\n", "\n", "# Let's remove 'sometimes'\n", - "my_list.____('sometimes')\n", + "my_list.____(\"sometimes\")\n", "\n", "# Let's change the second item\n", - "my_list[____] = 'is neat'" + "my_list[____] = \"is neat\"" ] }, { @@ -38,7 +38,7 @@ "outputs": [], "source": [ "# Let's verify that it's correct\n", - "assert my_list == ['Python', 'is neat']" + "assert my_list == [\"Python\", \"is neat\"]" ] }, { @@ -56,7 +56,7 @@ }, "outputs": [], "source": [ - "original = ['I', 'am', 'learning', 'hacking', 'in']" + "original = [\"I\", \"am\", \"learning\", \"hacking\", \"in\"]" ] }, { @@ -77,8 +77,8 @@ }, "outputs": [], "source": [ - "assert original == ['I', 'am', 'learning', 'hacking', 'in']\n", - "assert modified == ['I', 'am', 'learning', 'lists', 'in', 'Python']" + "assert original == [\"I\", \"am\", \"learning\", \"hacking\", \"in\"]\n", + "assert modified == [\"I\", \"am\", \"learning\", \"lists\", \"in\", \"Python\"]" ] }, { @@ -115,8 +115,7 @@ "cell_type": "code", "execution_count": null, "metadata": { - "editable": false, - "scrolled": true + "editable": false }, "outputs": [], "source": [ diff --git a/notebooks/beginner/exercises/dictionaries_exercise.ipynb b/notebooks/beginner/exercises/05_dictionaries_exercise.ipynb similarity index 71% rename from notebooks/beginner/exercises/dictionaries_exercise.ipynb rename to notebooks/beginner/exercises/05_dictionaries_exercise.ipynb index 06b3b07..76cb804 100644 --- a/notebooks/beginner/exercises/dictionaries_exercise.ipynb +++ b/notebooks/beginner/exercises/05_dictionaries_exercise.ipynb @@ -16,10 +16,10 @@ }, "outputs": [], "source": [ - "first_name = 'John'\n", - "last_name = 'Doe'\n", - "favorite_hobby = 'Python'\n", - "sports_hobby = 'gym'\n", + "first_name = \"John\"\n", + "last_name = \"Doe\"\n", + "favorite_hobby = \"Python\"\n", + "sports_hobby = \"gym\"\n", "age = 82" ] }, @@ -41,11 +41,7 @@ }, "outputs": [], "source": [ - "assert my_dict == {\n", - " 'name': 'John Doe',\n", - " 'age': 82,\n", - " 'hobbies': ['Python', 'gym']\n", - " }" + "assert my_dict == {\"name\": \"John Doe\", \"age\": 82, \"hobbies\": [\"Python\", \"gym\"]}" ] }, { @@ -64,10 +60,10 @@ }, "outputs": [], "source": [ - "dict1 = dict(key1='This is not that hard', key2='Python is still cool')\n", - "dict2 = {'key1': 123, 'special_key': 'secret'}\n", - "# This is also a away to initialize a dict (list of tuples) \n", - "dict3 = dict([('key2', 456), ('keyX', 'X')])" + "dict1 = dict(key1=\"This is not that hard\", key2=\"Python is still cool\")\n", + "dict2 = {\"key1\": 123, \"special_key\": \"secret\"}\n", + "# This is also a away to initialize a dict (list of tuples)\n", + "dict3 = dict([(\"key2\", 456), (\"keyX\", \"X\")])" ] }, { @@ -89,16 +85,13 @@ }, "outputs": [], "source": [ - "assert my_dict == {'key1': 123, 'key2': 456, 'keyX': 'X'}\n", - "assert special_value == 'secret'\n", + "assert my_dict == {\"key1\": 123, \"key2\": 456, \"keyX\": \"X\"}\n", + "assert special_value == \"secret\"\n", "\n", "# Let's check that the originals are untouched\n", - "assert dict1 == {\n", - " 'key1': 'This is not that hard',\n", - " 'key2': 'Python is still cool'\n", - " }\n", - "assert dict2 == {'key1': 123, 'special_key': 'secret'}\n", - "assert dict3 == {'key2': 456, 'keyX': 'X'}" + "assert dict1 == {\"key1\": \"This is not that hard\", \"key2\": \"Python is still cool\"}\n", + "assert dict2 == {\"key1\": 123, \"special_key\": \"secret\"}\n", + "assert dict3 == {\"key2\": 456, \"keyX\": \"X\"}" ] } ], diff --git a/notebooks/beginner/exercises/for_loops_exercise.ipynb b/notebooks/beginner/exercises/06_for_loops_exercise.ipynb similarity index 85% rename from notebooks/beginner/exercises/for_loops_exercise.ipynb rename to notebooks/beginner/exercises/06_for_loops_exercise.ipynb index eae36c6..e429308 100644 --- a/notebooks/beginner/exercises/for_loops_exercise.ipynb +++ b/notebooks/beginner/exercises/06_for_loops_exercise.ipynb @@ -14,7 +14,7 @@ "metadata": {}, "outputs": [], "source": [ - "words = ['PYTHON', 'JOHN', 'chEEse', 'hAm', 'DOE', '123']\n", + "words = [\"PYTHON\", \"JOHN\", \"chEEse\", \"hAm\", \"DOE\", \"123\"]\n", "upper_case_words = []\n", "\n", "for ____ in words:\n", @@ -30,7 +30,7 @@ }, "outputs": [], "source": [ - "assert upper_case_words == ['PYTHON', 'JOHN', 'DOE']" + "assert upper_case_words == [\"PYTHON\", \"JOHN\", \"DOE\"]" ] }, { @@ -49,7 +49,7 @@ }, "outputs": [], "source": [ - "magic_dict = dict(val1=44, val2='secret value', val3=55.0, val4=1)" + "magic_dict = dict(val1=44, val2=\"secret value\", val3=55.0, val4=1)" ] }, { @@ -114,7 +114,16 @@ }, "outputs": [], "source": [ - "assert my_list == ['odd', 'odd', 'even', 'even', 'odd', 'five even', 'five even', 'five odd']" + "assert my_list == [\n", + " \"odd\",\n", + " \"odd\",\n", + " \"even\",\n", + " \"even\",\n", + " \"odd\",\n", + " \"five even\",\n", + " \"five even\",\n", + " \"five odd\",\n", + "]" ] } ], diff --git a/notebooks/beginner/exercises/functions_exercise.ipynb b/notebooks/beginner/exercises/07_functions_exercise.ipynb similarity index 83% rename from notebooks/beginner/exercises/functions_exercise.ipynb rename to notebooks/beginner/exercises/07_functions_exercise.ipynb index 64f891e..6682f56 100644 --- a/notebooks/beginner/exercises/functions_exercise.ipynb +++ b/notebooks/beginner/exercises/07_functions_exercise.ipynb @@ -51,7 +51,7 @@ }, "outputs": [], "source": [ - "WANTED_PEOPLE = ['John Doe', 'Clint Eastwood', 'Chuck Norris']" + "WANTED_PEOPLE = [\"John Doe\", \"Clint Eastwood\", \"Chuck Norris\"]" ] }, { @@ -71,13 +71,13 @@ }, "outputs": [], "source": [ - "people_to_check1 = ['Donald Duck', 'Clint Eastwood', 'John Doe', 'Barack Obama']\n", + "people_to_check1 = [\"Donald Duck\", \"Clint Eastwood\", \"John Doe\", \"Barack Obama\"]\n", "wanted1 = find_wanted_people(people_to_check1)\n", "assert len(wanted1) == 2\n", - "assert 'John Doe' in wanted1\n", - "assert 'Clint Eastwood'in wanted1\n", + "assert \"John Doe\" in wanted1\n", + "assert \"Clint Eastwood\" in wanted1\n", "\n", - "people_to_check2 = ['Donald Duck', 'Mickey Mouse', 'Zorro', 'Superman', 'Robin Hood']\n", + "people_to_check2 = [\"Donald Duck\", \"Mickey Mouse\", \"Zorro\", \"Superman\", \"Robin Hood\"]\n", "wanted2 = find_wanted_people(people_to_check2)\n", "assert wanted2 == []" ] @@ -107,10 +107,10 @@ }, "outputs": [], "source": [ - "assert average_length_of_words('only four lett erwo rdss') == 4\n", - "assert average_length_of_words('one two three') == 3.7\n", - "assert average_length_of_words('one two three four') == 3.8\n", - "assert average_length_of_words('') == 0" + "assert average_length_of_words(\"only four lett erwo rdss\") == 4\n", + "assert average_length_of_words(\"one two three\") == 3.7\n", + "assert average_length_of_words(\"one two three four\") == 3.8\n", + "assert average_length_of_words(\"\") == 0" ] } ], diff --git a/notebooks/beginner/exercises/testing1_exercise.ipynb b/notebooks/beginner/exercises/08_testing1_exercise.ipynb similarity index 91% rename from notebooks/beginner/exercises/testing1_exercise.ipynb rename to notebooks/beginner/exercises/08_testing1_exercise.ipynb index f202c21..ea7219c 100644 --- a/notebooks/beginner/exercises/testing1_exercise.ipynb +++ b/notebooks/beginner/exercises/08_testing1_exercise.ipynb @@ -8,13 +8,14 @@ "source": [ "# Required boilerplate\n", "import sys\n", + "\n", "!{sys.executable} -m pip install pytest\n", "!{sys.executable} -m pip install ipytest\n", "\n", "import ipytest.magics\n", "import pytest\n", "\n", - "__file__ = 'testing1_exercise.ipynb'" + "__file__ = \"testing1_exercise.ipynb\"" ] }, { @@ -34,7 +35,7 @@ "outputs": [], "source": [ "def get_divisible_by_five(numbers):\n", - " '''Returns a list of numbers which are divisible by five in the list got as an argument'''\n", + " \"\"\"Returns a list of numbers which are divisible by five in the list got as an argument\"\"\"\n", " result = []\n", " for num in numbers:\n", " if not num % 5:\n", diff --git a/notebooks/beginner/exercises/recap1_exercise.ipynb b/notebooks/beginner/exercises/09_recap1_exercise.ipynb similarity index 79% rename from notebooks/beginner/exercises/recap1_exercise.ipynb rename to notebooks/beginner/exercises/09_recap1_exercise.ipynb index ea0d342..1212ccb 100644 --- a/notebooks/beginner/exercises/recap1_exercise.ipynb +++ b/notebooks/beginner/exercises/09_recap1_exercise.ipynb @@ -16,7 +16,7 @@ }, "outputs": [], "source": [ - "VOWELS = ['a', 'e', 'i', 'o', 'u']" + "VOWELS = [\"a\", \"e\", \"i\", \"o\", \"u\"]" ] }, { @@ -36,8 +36,8 @@ }, "outputs": [], "source": [ - "assert super_vowels('hi wassup!') == 'hI wAssUp!'\n", - "assert super_vowels('HOw aRE You?') == 'hOw ArE yOU?'" + "assert super_vowels(\"hi wassup!\") == \"hI wAssUp!\"\n", + "assert super_vowels(\"HOw aRE You?\") == \"hOw ArE yOU?\"" ] }, { @@ -65,25 +65,19 @@ }, "outputs": [], "source": [ - "board_of_5 = (\n", - "' * * \\n'\n", - "'* * *\\n'\n", - "' * * \\n'\n", - "'* * *\\n'\n", - "' * * \\n'\n", - ")\n", + "board_of_5 = \" * * \\n\" \"* * *\\n\" \" * * \\n\" \"* * *\\n\" \" * * \\n\"\n", "\n", "board_of_10 = (\n", - "' * * * * *\\n'\n", - "'* * * * * \\n'\n", - "' * * * * *\\n'\n", - "'* * * * * \\n'\n", - "' * * * * *\\n'\n", - "'* * * * * \\n'\n", - "' * * * * *\\n'\n", - "'* * * * * \\n'\n", - "' * * * * *\\n'\n", - "'* * * * * \\n'\n", + " \" * * * * *\\n\"\n", + " \"* * * * * \\n\"\n", + " \" * * * * *\\n\"\n", + " \"* * * * * \\n\"\n", + " \" * * * * *\\n\"\n", + " \"* * * * * \\n\"\n", + " \" * * * * *\\n\"\n", + " \"* * * * * \\n\"\n", + " \" * * * * *\\n\"\n", + " \"* * * * * \\n\"\n", ")\n", "\n", "assert get_playing_board(5) == board_of_5\n", diff --git a/notebooks/beginner/exercises/file_io_exercise.ipynb b/notebooks/beginner/exercises/10_file_io_exercise.ipynb similarity index 85% rename from notebooks/beginner/exercises/file_io_exercise.ipynb rename to notebooks/beginner/exercises/10_file_io_exercise.ipynb index 40ea966..2fcb284 100644 --- a/notebooks/beginner/exercises/file_io_exercise.ipynb +++ b/notebooks/beginner/exercises/10_file_io_exercise.ipynb @@ -14,7 +14,7 @@ "\n", "# Constants for the exercises:\n", "WORKING_DIR = os.getcwd()\n", - "DATA_DIR = os.path.join(os.path.dirname(WORKING_DIR), 'data')" + "DATA_DIR = os.path.join(os.path.dirname(WORKING_DIR), \"data\")" ] }, { @@ -35,7 +35,7 @@ " sum_ = 0 # A common way to use variable names that collide with built-in/keyword words is to add underscore\n", " with ____(input_file, ____) as ____:\n", " for line in ____:\n", - " ____ = line.strip() # Remove potential white space \n", + " ____ = line.strip() # Remove potential white space\n", " ____ += float(____)\n", " return ____" ] @@ -48,7 +48,7 @@ }, "outputs": [], "source": [ - "in_file = os.path.join(DATA_DIR, 'numbers.txt')\n", + "in_file = os.path.join(DATA_DIR, \"numbers.txt\")\n", "assert sum_numbers_in_file(in_file) == 189.5" ] }, @@ -77,13 +77,13 @@ }, "outputs": [], "source": [ - "in_file1 = os.path.join(DATA_DIR, 'simple_file.txt')\n", - "in_file2 = os.path.join(DATA_DIR, 'simple_file_with_empty_lines.txt')\n", + "in_file1 = os.path.join(DATA_DIR, \"simple_file.txt\")\n", + "in_file2 = os.path.join(DATA_DIR, \"simple_file_with_empty_lines.txt\")\n", "\n", - "expected_file_1 = ['First', 'Second', 'Third', 'And']\n", + "expected_file_1 = [\"First\", \"Second\", \"Third\", \"And\"]\n", "assert find_first_words(in_file1) == expected_file_1\n", "\n", - "expected_file_2 = ['The', '', 'First', 'nonsense', '', 'Then']\n", + "expected_file_2 = [\"The\", \"\", \"First\", \"nonsense\", \"\", \"Then\"]\n", "assert find_first_words(in_file2) == expected_file_2" ] } diff --git a/notebooks/beginner/exercises/classes_exercise.ipynb b/notebooks/beginner/exercises/11_classes_exercise.ipynb similarity index 90% rename from notebooks/beginner/exercises/classes_exercise.ipynb rename to notebooks/beginner/exercises/11_classes_exercise.ipynb index 5e60c49..2313b1c 100644 --- a/notebooks/beginner/exercises/classes_exercise.ipynb +++ b/notebooks/beginner/exercises/11_classes_exercise.ipynb @@ -18,10 +18,10 @@ " def __init__(self, var1, ____):\n", " self.____ = var1\n", " self.____ = _____\n", - " \n", + "\n", " def calculate_power(self):\n", - " return self.____ ** ____.____\n", - " \n", + " return self.____**____.____\n", + "\n", " def calculate_sum(____, var3):\n", " return ____.____ + ____.____ + var3" ] @@ -80,16 +80,16 @@ }, "outputs": [], "source": [ - "assert StringManipulator.__doc__ == 'Docstring of StringManipulator'\n", - "assert StringManipulator.category == 'Manipulator'\n", + "assert StringManipulator.__doc__ == \"Docstring of StringManipulator\"\n", + "assert StringManipulator.category == \"Manipulator\"\n", "\n", - "str_manip = StringManipulator('cOOL pyThON')\n", + "str_manip = StringManipulator(\"cOOL pyThON\")\n", "\n", "str_manip.reverse_words()\n", - "assert str_manip.get_manipulated() == 'pyThON cOOL'\n", + "assert str_manip.get_manipulated() == \"pyThON cOOL\"\n", "\n", "str_manip.make_title()\n", - "assert str_manip.get_manipulated() == 'Python Cool'" + "assert str_manip.get_manipulated() == \"Python Cool\"" ] }, { diff --git a/notebooks/beginner/exercises/exceptions_exercise.ipynb b/notebooks/beginner/exercises/12_exceptions_exercise.ipynb similarity index 88% rename from notebooks/beginner/exercises/exceptions_exercise.ipynb rename to notebooks/beginner/exercises/12_exceptions_exercise.ipynb index 61278cf..68e2e8f 100644 --- a/notebooks/beginner/exercises/exceptions_exercise.ipynb +++ b/notebooks/beginner/exercises/12_exceptions_exercise.ipynb @@ -34,10 +34,10 @@ "outputs": [], "source": [ "list1 = [1, 2, 3]\n", - "list2 = ['1', 2.5, '3.0']\n", - "list3 = ['', '1']\n", + "list2 = [\"1\", 2.5, \"3.0\"]\n", + "list3 = [\"\", \"1\"]\n", "list4 = []\n", - "list5 = ['John', 'Doe', 'was', 'here']\n", + "list5 = [\"John\", \"Doe\", \"was\", \"here\"]\n", "nasty_list = [KeyError(), [], dict()]\n", "\n", "assert sum_of_list(list1) == 6\n", @@ -74,24 +74,24 @@ "outputs": [], "source": [ "# These should not raise\n", - "verify_short_string('short') \n", - "verify_short_string('10 chars')\n", + "verify_short_string(\"short\")\n", + "verify_short_string(\"10 chars\")\n", "\n", "# This should raise\n", "try:\n", - " verify_short_string('this is long')\n", + " verify_short_string(\"this is long\")\n", "except TooLongString as e:\n", " # This is ok\n", " pass\n", "else:\n", " # This means that there was no exception\n", - " assert False " + " assert False" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, diff --git a/notebooks/beginner/exercises/debugging_exercise.ipynb b/notebooks/beginner/exercises/14_debugging_exercise.ipynb similarity index 87% rename from notebooks/beginner/exercises/debugging_exercise.ipynb rename to notebooks/beginner/exercises/14_debugging_exercise.ipynb index d19bc83..6bfbf4e 100644 --- a/notebooks/beginner/exercises/debugging_exercise.ipynb +++ b/notebooks/beginner/exercises/14_debugging_exercise.ipynb @@ -19,7 +19,7 @@ "def stripped_reversed_lowercase(original):\n", " # Set a breakpoint here and start debugging\n", " stripped = original.lstrip()\n", - " reversed = ' '.join(reversed(stripped))\n", + " reversed = \" \".join(reversed(stripped))\n", " reversed.lower()\n", " return reversed" ] @@ -33,15 +33,15 @@ "outputs": [], "source": [ "# Let's verify it works\n", - "original = ' \\n Original String '\n", + "original = \" \\n Original String \"\n", "result = stripped_reversed_lowercase(original)\n", - "assert result == 'gnirts lanigiro'" + "assert result == \"gnirts lanigiro\"" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -55,7 +55,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.10.3" } }, "nbformat": 4, diff --git a/notebooks/beginner/exercises/std_lib1_exercise.ipynb b/notebooks/beginner/exercises/15_std_lib1_exercise.ipynb similarity index 90% rename from notebooks/beginner/exercises/std_lib1_exercise.ipynb rename to notebooks/beginner/exercises/15_std_lib1_exercise.ipynb index 5e5eedf..4897a12 100644 --- a/notebooks/beginner/exercises/std_lib1_exercise.ipynb +++ b/notebooks/beginner/exercises/15_std_lib1_exercise.ipynb @@ -8,6 +8,7 @@ "source": [ "# pytz will be needed in the exercise\n", "import sys\n", + "\n", "!{sys.executable} -m pip install pytz" ] }, @@ -85,11 +86,11 @@ }, "outputs": [], "source": [ - "assert utc_dt.isoformat() == '2000-01-01T10:00:00+00:00'\n", - "assert sydney_dt.isoformat() == '2000-01-01T21:00:00+11:00'\n", - "assert la_dt.isoformat() == '2000-01-01T02:00:00-08:00'\n", + "assert utc_dt.isoformat() == \"2000-01-01T10:00:00+00:00\"\n", + "assert sydney_dt.isoformat() == \"2000-01-01T21:00:00+11:00\"\n", + "assert la_dt.isoformat() == \"2000-01-01T02:00:00-08:00\"\n", "\n", - "print('All good!')" + "print(\"All good!\")" ] } ], diff --git a/notebooks/beginner/exercises/testing2_exercise.ipynb b/notebooks/beginner/exercises/16_testing2_exercise.ipynb similarity index 96% rename from notebooks/beginner/exercises/testing2_exercise.ipynb rename to notebooks/beginner/exercises/16_testing2_exercise.ipynb index cab0169..d3862db 100644 --- a/notebooks/beginner/exercises/testing2_exercise.ipynb +++ b/notebooks/beginner/exercises/16_testing2_exercise.ipynb @@ -8,13 +8,14 @@ "source": [ "# Required boilerplate\n", "import sys\n", + "\n", "!{sys.executable} -m pip install pytest\n", "!{sys.executable} -m pip install ipytest\n", "\n", "import ipytest.magics\n", "import pytest\n", "\n", - "__file__ = 'testing2_exercise.ipynb'" + "__file__ = \"testing2_exercise.ipynb\"" ] }, { @@ -57,14 +58,14 @@ "\n", " def complete(self, number):\n", " if number not in self._todo:\n", - " raise TodoNotFound('{} not in todos'.format(number))\n", + " raise TodoNotFound(\"{} not in todos\".format(number))\n", "\n", " task = self._todo.pop(number)\n", " self._done[number] = task\n", "\n", " def remove(self, number):\n", " if number not in self._todo:\n", - " raise TodoNotFound('{} not in todos'.format(number))\n", + " raise TodoNotFound(\"{} not in todos\".format(number))\n", "\n", " del self._todo[number]" ] diff --git a/notebooks/beginner/exercises/recap2_exercise.ipynb b/notebooks/beginner/exercises/19_recap2_exercise.ipynb similarity index 80% rename from notebooks/beginner/exercises/recap2_exercise.ipynb rename to notebooks/beginner/exercises/19_recap2_exercise.ipynb index bd6b2d5..e5811e5 100644 --- a/notebooks/beginner/exercises/recap2_exercise.ipynb +++ b/notebooks/beginner/exercises/19_recap2_exercise.ipynb @@ -21,8 +21,8 @@ "PAPER = 2\n", "SCISSORS = 3\n", "\n", - "PLAYER_WINS = 'Player wins!! Woop woop!'\n", - "COMPUTER_WINS = 'Robocop wins :-('\n", + "PLAYER_WINS = \"Player wins!! Woop woop!\"\n", + "COMPUTER_WINS = \"Robocop wins :-(\"\n", "TIE = \"It's a tie!\"" ] }, @@ -32,7 +32,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Your implementation here\n" + "# Your implementation here" ] }, { @@ -49,20 +49,21 @@ "outputs": [], "source": [ "def play_rps():\n", - " print('Welcome to play rock-paper-scissors')\n", - " print('The options are:\\nrock: 1\\npaper: 2\\nscissors: 3')\n", + " print(\"Welcome to play rock-paper-scissors\")\n", + " print(\"The options are:\\nrock: 1\\npaper: 2\\nscissors: 3\")\n", "\n", " result = TIE\n", " while result == TIE:\n", - " player_choice = input('Give your choice\\n')\n", - " \n", - " if not player_choice in ['1', '2', '3']:\n", - " print('Invalid choice')\n", + " player_choice = input(\"Give your choice\\n\")\n", + "\n", + " if not player_choice in [\"1\", \"2\", \"3\"]:\n", + " print(\"Invalid choice\")\n", " continue\n", - " \n", + "\n", " result = rock_paper_scissors(int(player_choice))\n", - " \n", - "if __name__ == '__main__':\n", + "\n", + "\n", + "if __name__ == \"__main__\":\n", " play_rps()" ] }, @@ -109,7 +110,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Your implementation here\n" + "# Your implementation here" ] }, { @@ -128,9 +129,10 @@ "outputs": [], "source": [ "import os\n", + "\n", "WORKING_DIR = os.getcwd()\n", - "DATA_DIR = os.path.join(os.path.dirname(WORKING_DIR), 'data')\n", - "DATA_FILE = os.path.join(DATA_DIR, 'random_data.txt')\n", + "DATA_DIR = os.path.join(os.path.dirname(WORKING_DIR), \"data\")\n", + "DATA_FILE = os.path.join(DATA_DIR, \"random_data.txt\")\n", "\n", "da = DataAnalyzer(DATA_FILE)\n", "\n", @@ -144,13 +146,14 @@ "print(report)\n", "\n", "expected_report = (\n", - "'Report for random_data.txt\\n'\n", - "'samples: 20\\n'\n", - "'average: 49.35\\n'\n", - "'median: 47.50\\n'\n", - "'max: 94.00\\n'\n", - "'min: 4.00')\n", - "assert report == expected_report " + " \"Report for random_data.txt\\n\"\n", + " \"samples: 20\\n\"\n", + " \"average: 49.35\\n\"\n", + " \"median: 47.50\\n\"\n", + " \"max: 94.00\\n\"\n", + " \"min: 4.00\"\n", + ")\n", + "assert report == expected_report" ] }, { @@ -168,12 +171,12 @@ }, "outputs": [], "source": [ - "EMPTY_FILE = os.path.join(DATA_DIR, 'empty_file.txt')\n", + "EMPTY_FILE = os.path.join(DATA_DIR, \"empty_file.txt\")\n", "try:\n", " da_empty = DataAnalyzer(EMPTY_FILE)\n", "except NoData:\n", - " print('All ok :)')\n", - "else: # There was no exception\n", + " print(\"All ok :)\")\n", + "else: # There was no exception\n", " assert False" ] } diff --git a/notebooks/beginner/html/01_strings.html b/notebooks/beginner/html/01_strings.html new file mode 100644 index 0000000..5355ce0 --- /dev/null +++ b/notebooks/beginner/html/01_strings.html @@ -0,0 +1,16216 @@ + + + + + +01_strings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/02_numbers.html b/notebooks/beginner/html/02_numbers.html new file mode 100644 index 0000000..ae0fc6e --- /dev/null +++ b/notebooks/beginner/html/02_numbers.html @@ -0,0 +1,15613 @@ + + + + + +02_numbers + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/03_conditionals.html b/notebooks/beginner/html/03_conditionals.html new file mode 100644 index 0000000..160f64f --- /dev/null +++ b/notebooks/beginner/html/03_conditionals.html @@ -0,0 +1,15893 @@ + + + + + +03_conditionals + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/04_lists.html b/notebooks/beginner/html/04_lists.html new file mode 100644 index 0000000..979781e --- /dev/null +++ b/notebooks/beginner/html/04_lists.html @@ -0,0 +1,15917 @@ + + + + + +04_lists + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/05_dictionaries.html b/notebooks/beginner/html/05_dictionaries.html new file mode 100644 index 0000000..6eaa9fc --- /dev/null +++ b/notebooks/beginner/html/05_dictionaries.html @@ -0,0 +1,15843 @@ + + + + + +05_dictionaries + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/06_for_loops.html b/notebooks/beginner/html/06_for_loops.html new file mode 100644 index 0000000..933d5bc --- /dev/null +++ b/notebooks/beginner/html/06_for_loops.html @@ -0,0 +1,15577 @@ + + + + + +06_for_loops + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/07_functions.html b/notebooks/beginner/html/07_functions.html new file mode 100644 index 0000000..6a34ddc --- /dev/null +++ b/notebooks/beginner/html/07_functions.html @@ -0,0 +1,15675 @@ + + + + + +07_functions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/08_testing1.html b/notebooks/beginner/html/08_testing1.html new file mode 100644 index 0000000..386da09 --- /dev/null +++ b/notebooks/beginner/html/08_testing1.html @@ -0,0 +1,15376 @@ + + + + + +08_testing1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/10_file_io.html b/notebooks/beginner/html/10_file_io.html new file mode 100644 index 0000000..de470b5 --- /dev/null +++ b/notebooks/beginner/html/10_file_io.html @@ -0,0 +1,15414 @@ + + + + + +10_file_io + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/11_classes.html b/notebooks/beginner/html/11_classes.html new file mode 100644 index 0000000..0df09e5 --- /dev/null +++ b/notebooks/beginner/html/11_classes.html @@ -0,0 +1,15744 @@ + + + + + +11_classes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/12_exceptions.html b/notebooks/beginner/html/12_exceptions.html new file mode 100644 index 0000000..4e15a10 --- /dev/null +++ b/notebooks/beginner/html/12_exceptions.html @@ -0,0 +1,15380 @@ + + + + + +12_exceptions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/13_modules_and_packages.html b/notebooks/beginner/html/13_modules_and_packages.html new file mode 100644 index 0000000..db32a4d --- /dev/null +++ b/notebooks/beginner/html/13_modules_and_packages.html @@ -0,0 +1,15231 @@ + + + + + +13_modules_and_packages + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/14_debugging.html b/notebooks/beginner/html/14_debugging.html new file mode 100644 index 0000000..0ce26e2 --- /dev/null +++ b/notebooks/beginner/html/14_debugging.html @@ -0,0 +1,15247 @@ + + + + + +14_debugging + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/15_std_lib.html b/notebooks/beginner/html/15_std_lib.html new file mode 100644 index 0000000..b8263d6 --- /dev/null +++ b/notebooks/beginner/html/15_std_lib.html @@ -0,0 +1,15973 @@ + + + + + +15_std_lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/16_testing2.html b/notebooks/beginner/html/16_testing2.html new file mode 100644 index 0000000..d4c189c --- /dev/null +++ b/notebooks/beginner/html/16_testing2.html @@ -0,0 +1,15487 @@ + + + + + +16_testing2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/17_venv.html b/notebooks/beginner/html/17_venv.html new file mode 100644 index 0000000..6f3ea05 --- /dev/null +++ b/notebooks/beginner/html/17_venv.html @@ -0,0 +1,15205 @@ + + + + + +17_venv + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/18_project_structure.html b/notebooks/beginner/html/18_project_structure.html new file mode 100644 index 0000000..17fb4b0 --- /dev/null +++ b/notebooks/beginner/html/18_project_structure.html @@ -0,0 +1,15251 @@ + + + + + +18_project_structure + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/beginner/html/classes.html b/notebooks/beginner/html/classes.html deleted file mode 100644 index 78d9d42..0000000 --- a/notebooks/beginner/html/classes.html +++ /dev/null @@ -1,12335 +0,0 @@ - - - -tmp_classes - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
- -
-
-
-
-
In [1]:
-
-
-
class MyFirstClass:
-    def __init__(self, name):
-        self.name = name
-
-    def greet(self):
-        print('Hello {}!'.format(self.name))
-
- -
-
-
- -
-
-
-
In [2]:
-
-
-
my_instance = MyFirstClass('John Doe')
-print('my_instance: {}'.format(my_instance))
-print('type: {}'.format(type(my_instance)))
-print('my_instance.name: {}'.format(my_instance.name))
-
- -
-
-
- -
-
- - -
- -
- - -
-
my_instance: <__main__.MyFirstClass object at 0x106a18588>
-type: <class '__main__.MyFirstClass'>
-my_instance.name: John Doe
-
-
-
- -
-
- -
-
-
-
-
-

Methods

The functions inside classes are called methods. They are used similarly as functions.

- -
-
-
-
-
-
In [3]:
-
-
-
alice = MyFirstClass(name='Alice')
-alice.greet()
-
- -
-
-
- -
-
- - -
- -
- - -
-
Hello Alice!
-
-
-
- -
-
- -
-
-
-
-
-

__init__()

__init__() is a special method that is used for initialising instances of the class. It's called when you create an instance of the class.

- -
-
-
-
-
-
In [4]:
-
-
-
class Example:
-    def __init__(self):
-        print('Now we are inside __init__')
-        
-print('creating instance of Example')
-example = Example()
-print('instance created')
-
- -
-
-
- -
-
- - -
- -
- - -
-
creating instance of Example
-Now we are inside __init__
-instance created
-
-
-
- -
-
- -
-
-
-
-
-

__init__() is typically used for initialising instance variables of your class. These can be listed as arguments after self. To be able to access these instance variables later during your instance's lifetime, you have to save them into self. self is the first argument of the methods of your class and it's your access to the instance variables and other methods.

- -
-
-
-
-
-
In [5]:
-
-
-
class Example:
-    def __init__(self, var1, var2):
-        self.first_var = var1
-        self.second_var = var2
-        
-    def print_variables(self):
-        print('{} {}'.format(self.first_var, self.second_var))
-        
-e = Example('abc', 123)
-e.print_variables()
-    
-
- -
-
-
- -
-
- - -
- -
- - -
-
abc 123
-
-
-
- -
-
- -
-
-
-
-
-

__str__()

__str__() is a special method which is called when an instance of the class is converted to string (e.g. when you want to print the instance). In other words, by defining __str__ method for your class, you can decide what's the printable version of the instances of your class. The method should return a string.

- -
-
-
-
-
-
In [6]:
-
-
-
class Person:
-    def __init__(self, name, age):
-        self.name = name
-        self.age = age
-        
-    def __str__(self):
-        return 'Person: {}'.format(self.name)
-    
-jack = Person('Jack', 82)
-print('This is the string presentation of jack: {}'.format(jack))
-
- -
-
-
- -
-
- - -
- -
- - -
-
This is the string presentation of jack: Person: Jack
-
-
-
- -
-
- -
-
-
-
-
-

Class variables vs instance variables

Class variables are shared between all the instances of that class whereas instance variables can hold different values between different instances of that class.

- -
-
-
-
-
-
In [7]:
-
-
-
class Example:
-    # These are class variables
-    name = 'Example class'
-    description = 'Just an example of a simple class'
-
-    def __init__(self, var1):
-        # This is an instance variable
-        self.instance_variable = var1
-
-    def show_info(self):
-        info = 'instance_variable: {}, name: {}, description: {}'.format(
-            self.instance_variable, Example.name, Example.description)
-        print(info)
-
-
-inst1 = Example('foo')
-inst2 = Example('bar')
-
-# name and description have identical values between instances
-assert inst1.name == inst2.name == Example.name
-assert inst1.description == inst2.description == Example.description
-
-# If you change the value of a class variable, it's changed across all instances
-Example.name = 'Modified name'
-inst1.show_info()
-inst2.show_info()
-
- -
-
-
- -
-
- - -
- -
- - -
-
instance_variable: foo, name: Modified name, description: Just an example of a simple class
-instance_variable: bar, name: Modified name, description: Just an example of a simple class
-
-
-
- -
-
- -
-
-
-
-
-

Public vs private

In python there's now strict separation for private/public methods or instance variables. The convention is to start the name of the method or instance variable with underscore if it should be treated as private. Private means that it should not be accessed from outside of the class.

-

For example, let's consider that we have a Person class which has age as an instance variable. We want that age is not directly accessed (e.g. changed) after the instance is created. In Python, this would be:

- -
-
-
-
-
-
In [8]:
-
-
-
class Person:
-    def __init__(self, age):
-        self._age = age
-        
-example_person = Person(age=15)
-# You can't do this:
-# print(example_person.age)
-# Nor this:
-# example_person.age = 16
-
- -
-
-
- -
-
-
-
-
-

If you want the age to be readable but not writable, you can use property:

- -
-
-
-
-
-
In [9]:
-
-
-
class Person:
-    def __init__(self, age):
-        self._age = age
-        
-    @property
-    def age(self):
-        return self._age
-        
-example_person = Person(age=15)
-# Now you can do this:
-print(example_person.age)
-# But not this:
-#example_person.age = 16
-
- -
-
-
- -
-
- - -
- -
- - -
-
15
-
-
-
- -
-
- -
-
-
-
-
-

This way you can have a controlled access to the instance variables of your class:

- -
-
-
-
-
-
In [10]:
-
-
-
class Person:
-    def __init__(self, age):
-        self._age = age
-        
-    @property
-    def age(self):
-        return self._age
-    
-    def celebrate_birthday(self):
-        self._age += 1
-        print('Happy bday for {} years old!'.format(self._age))
-        
-example_person = Person(age=15)
-example_person.celebrate_birthday()
-
- -
-
-
- -
-
- - -
- -
- - -
-
Happy bday for 16 years old!
-
-
-
- -
-
- -
-
-
-
-
-

Introduction to inheritance

-
-
-
-
-
-
In [11]:
-
-
-
class Animal:
-    def greet(self):
-        print('Hello, I am an animal')
-
-    @property
-    def favorite_food(self):
-        return 'beef'
-
-
-class Dog(Animal):
-    def greet(self):
-        print('wof wof')
-
-
-class Cat(Animal):
-    @property
-    def favorite_food(self):
-        return 'fish'
-
- -
-
-
- -
-
-
-
In [12]:
-
-
-
dog = Dog()
-dog.greet()
-print("Dog's favorite food is {}".format(dog.favorite_food))
-
-cat = Cat()
-cat.greet()
-print("Cat's favorite food is {}".format(cat.favorite_food))
-
- -
-
-
- -
-
- - -
- -
- - -
-
wof wof
-Dog's favorite food is beef
-Hello, I am an animal
-Cat's favorite food is fish
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/conditionals.html b/notebooks/beginner/html/conditionals.html deleted file mode 100644 index 7f500c1..0000000 --- a/notebooks/beginner/html/conditionals.html +++ /dev/null @@ -1,12397 +0,0 @@ - - - -tmp_conditionals - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Conditionals

-
-
-
-
-
-
-
-

Testing truth value

-
-
-
-
-
-
-
-

bool

-
-
-
-
-
-
In [1]:
-
-
-
print('type of True and False: {}'.format(type(True)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
type of True and False: <class 'bool'>
-
-
-
- -
-
- -
-
-
-
In [2]:
-
-
-
print('0: {}, 1: {}'.format(bool(0), bool(1)))
-print('empty list: {}, list with values: {}'.format(bool([]), bool(['woop'])))
-print('empty dict: {}, dict with values: {}'.format(bool({}), bool({'Python': 'cool'})))
-
- -
-
-
- -
-
- - -
- -
- - -
-
0: False, 1: True
-empty list: False, list with values: True
-empty dict: False, dict with values: True
-
-
-
- -
-
- -
-
-
-
-
-

==, !=, >, <, >=, <=

-
-
-
-
-
-
In [3]:
-
-
-
print('1 == 0: {}'.format(1 == 0))
-print('1 != 0: {}'.format(1 != 0))
-print('1 > 0: {}'.format(1 > 0))
-print('1 > 1: {}'.format(1 > 1))
-print('1 < 0: {}'.format(1 < 0))
-print('1 < 1: {}'.format(1 < 1))
-print('1 >= 0: {}'.format(1 >= 0))
-print('1 >= 1: {}'.format(1 >= 1))
-print('1 <= 0: {}'.format(1 <= 0))
-print('1 <= 1: {}'.format(1 <= 1))
-
- -
-
-
- -
-
- - -
- -
- - -
-
1 == 0: False
-1 != 0: True
-1 > 0: True
-1 > 1: False
-1 < 0: False
-1 < 1: False
-1 >= 0: True
-1 >= 1: True
-1 <= 0: False
-1 <= 1: True
-
-
-
- -
-
- -
-
-
-
-
-

You can combine these:

- -
-
-
-
-
-
In [4]:
-
-
-
print('1 <= 2 <= 3: {}'.format(1 <= 2 <= 3))
-
- -
-
-
- -
-
- - -
- -
- - -
-
1 <= 2 <= 3: True
-
-
-
- -
-
- -
-
-
-
-
-

and, or, not

-
-
-
-
-
-
In [5]:
-
-
-
python_is_cool = True
-java_is_cool = False
-empty_list = []
-secret_value = 3.14
-
- -
-
-
- -
-
-
-
In [6]:
-
-
-
print('Python and java are both cool: {}'.format(python_is_cool and java_is_cool))
-print('secret_value and python_is_cool: {}'.format(secret_value and python_is_cool))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Python and java are both cool: False
-secret_value and python_is_cool: True
-
-
-
- -
-
- -
-
-
-
In [7]:
-
-
-
print('Python or java is cool: {}'.format(python_is_cool or java_is_cool))
-print('1 >= 1.1 or 2 < float("1.4"): {}'.format(1 >= 1.1 or 2 < float('1.4')))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Python or java is cool: True
-1 >= 1.1 or 2 < float("1.4"): False
-
-
-
- -
-
- -
-
-
-
In [8]:
-
-
-
print('Java is not cool: {}'.format(not java_is_cool))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Java is not cool: True
-
-
-
- -
-
- -
-
-
-
-
-

You can combine multiple statements, execution order is from left to right. You can control the execution order by using brackets.

- -
-
-
-
-
-
In [9]:
-
-
-
print(bool(not java_is_cool or secret_value and  python_is_cool or empty_list))
-print(bool(not (java_is_cool or secret_value and  python_is_cool or empty_list)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
True
-False
-
-
-
- -
-
- -
-
-
-
-
-

if

-
-
-
-
-
-
In [10]:
-
-
-
statement = True
-if statement:
-    print('statement is True')
-    
-if not statement:
-    print('statement is not True')
-
- -
-
-
- -
-
- - -
- -
- - -
-
statement is True
-
-
-
- -
-
- -
-
-
-
In [11]:
-
-
-
empty_list = []
-# With if and elif, conversion to `bool` is implicit
-if empty_list:
-    print('empty list will not evaluate to True')  # this won't be executed
-
- -
-
-
- -
-
-
-
In [12]:
-
-
-
val = 3
-if 0 <= val < 1 or val == 3:
-    print('Value is positive and less than one or value is three')
-
- -
-
-
- -
-
- - -
- -
- - -
-
Value is positive and less than one or value is three
-
-
-
- -
-
- -
-
-
-
-
-

if-else

-
-
-
-
-
-
In [13]:
-
-
-
my_dict = {}
-if my_dict:
-    print('there is something in my dict')
-else:
-    print('my dict is empty :(')
-
- -
-
-
- -
-
- - -
- -
- - -
-
my dict is empty :(
-
-
-
- -
-
- -
-
-
-
-
-

if-elif-else

-
-
-
-
-
-
In [14]:
-
-
-
val = 88
-if val >= 100:
-    print('value is equal or greater than 100')
-elif val > 10:
-    print('value is greater than 10 but less than 100')
-else:
-    print('value is equal or less than 10')
-
- -
-
-
- -
-
- - -
- -
- - -
-
value is greater than 10 but less than 100
-
-
-
- -
-
- -
-
-
-
-
-

You can have as many elif statements as you need. In addition, else at the end is not mandatory.

- -
-
-
-
-
-
In [15]:
-
-
-
greeting = 'Hello fellow Pythonista!'
-language = 'Italian'
-
-if language == 'Swedish':
-    greeting = 'Hejsan!'
-elif language == 'Finnish':
-    greeting = 'Latua perkele!'
-elif language == 'Spanish':
-    greeting = 'Hola!'
-elif language == 'German':
-    greeting = 'Guten Tag!'
-    
-print(greeting)
-
- -
-
-
- -
-
- - -
- -
- - -
-
Hello fellow Pythonista!
-
-
-
- -
-
- -
-
-
-
-
-

For more detailed overview about conditionals, check this tutorial from Real Python.

- -
-
-
-
-
- - - - - - diff --git a/notebooks/beginner/html/debugging.html b/notebooks/beginner/html/debugging.html deleted file mode 100644 index 5930372..0000000 --- a/notebooks/beginner/html/debugging.html +++ /dev/null @@ -1,11919 +0,0 @@ - - - -tmp_debugging - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Debugging with pdb

Your program does not always behave how you would expect it to behave. If the origin of the mistake is unclear, debugging is usually the most effective to find the root cause of the unexpected behavior. The Python Standard Library has a built-in debugger which is a powerful tool for solving any issues related to your code.

- -
-
-
-
-
-
-
-

import pdb; pdb.set_trace()

The basic use case for debugging is that you want to stop the execution of your program at some certain point and monitor variable values or program execution in general from that specific point onward. You stop the execution at the point you want by setting a breakpoint into code by import pdb; pdb.set_trace() (note in Python versions >= 3.7, there's a shortcut: breakpoint()).

-

When you execute your program, the execution will stop at this point and will enter to interactive debugger session. You can add as many breakpoints into your code as you want.

- -
-
-
-
-
-
-
-

Useful commands

See the full list here.

-
    -
  • h or help: Prints a list of available commands. If you give an argument, e.g. help continue, prints help of the continue command.
  • -
  • l or list: List a piece of code around the current position.
  • -
  • n or next: Execute next line.
  • -
  • s or step: Same as next but "steps into" the function called in the next line.
  • -
  • c or continue: Continue execution until next breakpoint.
  • -
  • r or return: Continue execution until the return of current function.
  • -
  • q or quit: Quit debugger and abort program execution.
  • -
-

Note that you can see the value of any variable by typing the variable name during the debugging session. You can also execute arbitrary code during the debugging session.

- -
-
-
-
-
-
-
-

Let's see how it works

Uncomment the import pdb; pdb.set_trace() lines and execute the cell. Execute the program line by line by using the commands defined above. Try all the above mentioned commands at least once. Pay attention to the difference between n and s.

- -
-
-
-
-
-
In [1]:
-
-
-
class SuperGreeter:
-    def __init__(self, people_to_greet):
-        self.people = people_to_greet
-
-    def greet(self):
-        for person in self.people:
-            if person.islower():
-                self._greet_street_style(person)
-            elif len(person) > 7:
-                self._greet_hawaii(person)
-            else:
-                self._greet_polite(person)
-            
-    def _greet_polite(self, name):
-        greeting = "G'day {}! How are you doing?".format(name)
-        print(greeting)
-
-    def _greet_street_style(self, name):
-        # import pdb; pdb.set_trace()  # UNCOMMENT
-        name = name.upper()
-        print('WASSUP {}!?'.format(name))
-
-    def _greet_hawaii(self, name):
-        print('Aloha {}!'.format(name))
-
-
-def main():
-    people = ['John Doe', 'Donald', 'Lisa', 'alex']
-    # import pdb; pdb.set_trace()  # UNCOMMENT
-    greeter = SuperGreeter(people)
-    greeter.greet()
-
-
-main()
-
- -
-
-
- -
-
- - -
- -
- - -
-
Aloha John Doe!
-G'day Donald! How are you doing?
-G'day Lisa! How are you doing?
-WASSUP ALEX!?
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/dictionaries.html b/notebooks/beginner/html/dictionaries.html deleted file mode 100644 index 46c6c58..0000000 --- a/notebooks/beginner/html/dictionaries.html +++ /dev/null @@ -1,12410 +0,0 @@ - - - -tmp_dictionaries - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Dictionaries

Collections of key-value pairs.

- -
-
-
-
-
-
In [1]:
-
-
-
my_empty_dict = {}  # alternative: my_empty_dict = dict()
-print('dict: {}, type: {}'.format(my_empty_dict, type(my_empty_dict)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
dict: {}, type: <class 'dict'>
-
-
-
- -
-
- -
-
-
-
-
-

Initialization

-
-
-
-
-
-
In [2]:
-
-
-
dict1 = {'value1': 1.6, 'value2': 10, 'name': 'John Doe'}
-dict2 = dict(value1=1.6, value2=10, name='John Doe')
-
-print(dict1)
-print(dict2)
-
-print('equal: {}'.format(dict1 == dict2))
-print('length: {}'.format(len(dict1)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'value1': 1.6, 'name': 'John Doe', 'value2': 10}
-{'value2': 10, 'name': 'John Doe', 'value1': 1.6}
-equal: True
-length: 3
-
-
-
- -
-
- -
-
-
-
-
-

dict.keys(), dict.values(), dict.items()

-
-
-
-
-
-
In [3]:
-
-
-
print('keys: {}'.format(dict1.keys()))
-print('values: {}'.format(dict1.values()))
-print('items: {}'.format(dict1.items()))
-
- -
-
-
- -
-
- - -
- -
- - -
-
keys: dict_keys(['value1', 'name', 'value2'])
-values: dict_values([1.6, 'John Doe', 10])
-items: dict_items([('value1', 1.6), ('name', 'John Doe'), ('value2', 10)])
-
-
-
- -
-
- -
-
-
-
-
-

Accessing and setting values

-
-
-
-
-
-
In [4]:
-
-
-
my_dict = {}
-my_dict['key1'] = 'value1'
-my_dict['key2'] = 99
-my_dict['key1'] = 'new value'  # overriding existing value
-print(my_dict)
-print('value of key1: {}'.format(my_dict['key1']))
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'key2': 99, 'key1': 'new value'}
-value of key1: new value
-
-
-
- -
-
- -
-
-
-
-
-

Accessing a nonexistent key will raise KeyError (see dict.get() for workaround):

- -
-
-
-
-
-
In [5]:
-
-
-
# print(my_dict['nope'])
-
- -
-
-
- -
-
-
-
-
-

Deleting

-
-
-
-
-
-
In [6]:
-
-
-
my_dict = {'key1': 'value1', 'key2': 99, 'keyX': 'valueX'}
-del my_dict['keyX']
-print(my_dict)
-
-# Usually better to make sure that the key exists (see also pop() and popitem())
-key_to_delete = 'my_key'
-if key_to_delete in my_dict:
-    del my_dict[key_to_delete]
-else:
-    print('{key} is not in {dictionary}'.format(key=key_to_delete, dictionary=my_dict))
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'key2': 99, 'key1': 'value1'}
-my_key is not in {'key2': 99, 'key1': 'value1'}
-
-
-
- -
-
- -
-
-
-
-
-

Dictionaries are mutable

-
-
-
-
-
-
In [7]:
-
-
-
my_dict = {'ham': 'good', 'carrot': 'semi good'}
-my_other_dict = my_dict
-my_other_dict['carrot'] = 'super tasty'
-my_other_dict['sausage'] = 'best ever'
-print('my_dict: {}\nother: {}'.format(my_dict, my_other_dict))
-print('equal: {}'.format(my_dict == my_other_dict))
-
- -
-
-
- -
-
- - -
- -
- - -
-
my_dict: {'carrot': 'super tasty', 'ham': 'good', 'sausage': 'best ever'}
-other: {'carrot': 'super tasty', 'ham': 'good', 'sausage': 'best ever'}
-equal: True
-
-
-
- -
-
- -
-
-
-
-
-

Create a new dict if you want to have a copy:

- -
-
-
-
-
-
In [8]:
-
-
-
my_dict = {'ham': 'good', 'carrot': 'semi good'}
-my_other_dict = dict(my_dict)
-my_other_dict['beer'] = 'decent'
-print('my_dict: {}\nother: {}'.format(my_dict, my_other_dict))
-print('equal: {}'.format(my_dict == my_other_dict))
-
- -
-
-
- -
-
- - -
- -
- - -
-
my_dict: {'carrot': 'semi good', 'ham': 'good'}
-other: {'beer': 'decent', 'carrot': 'semi good', 'ham': 'good'}
-equal: False
-
-
-
- -
-
- -
-
-
-
-
-

-

dict.get()

Returns None if key is not in dict. However, you can also specify default return value which will be returned if key is not present in the dict.

- -
-
-
-
-
-
In [9]:
-
-
-
my_dict = {'a': 1, 'b': 2, 'c': 3}
-d = my_dict.get('d')
-print('d: {}'.format(d))
-
-d = my_dict.get('d', 'my default value')
-print('d: {}'.format(d))
-
- -
-
-
- -
-
- - -
- -
- - -
-
d: None
-d: my default value
-
-
-
- -
-
- -
-
-
-
-
-

dict.pop()

-
-
-
-
-
-
In [10]:
-
-
-
my_dict = dict(food='ham', drink='beer', sport='football')
-print('dict before pops: {}'.format(my_dict))
-
-food = my_dict.pop('food')
-print('food: {}'.format(food))
-print('dict after popping food: {}'.format(my_dict))
-
-food_again = my_dict.pop('food', 'default value for food')
-print('food again: {}'.format(food_again))
-print('dict after popping food again: {}'.format(my_dict))
-
- -
-
-
- -
-
- - -
- -
- - -
-
dict before pops: {'sport': 'football', 'drink': 'beer', 'food': 'ham'}
-food: ham
-dict after popping food: {'sport': 'football', 'drink': 'beer'}
-food again: default value for food
-dict after popping food again: {'sport': 'football', 'drink': 'beer'}
-
-
-
- -
-
- -
-
-
-
-
-

dict.setdefault()

Returns the value of key defined as first parameter. If the key is not present in the dict, adds key with default value (second parameter).

- -
-
-
-
-
-
In [11]:
-
-
-
my_dict = {'a': 1, 'b': 2, 'c': 3}
-a = my_dict.setdefault('a', 'my default value')
-d = my_dict.setdefault('d', 'my default value')
-print('a: {}\nd: {}\nmy_dict: {}'.format(a, d, my_dict))
-
- -
-
-
- -
-
- - -
- -
- - -
-
a: 1
-d: my default value
-my_dict: {'a': 1, 'c': 3, 'b': 2, 'd': 'my default value'}
-
-
-
- -
-
- -
-
-
-
-
-

dict.update()

Merge two dicts

- -
-
-
-
-
-
In [12]:
-
-
-
dict1 = {'a': 1, 'b': 2}
-dict2 = {'c': 3}
-dict1.update(dict2)
-print(dict1)
-
-# If they have same keys:
-dict1.update({'c': 4})
-print(dict1)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'a': 1, 'c': 3, 'b': 2}
-{'a': 1, 'c': 4, 'b': 2}
-
-
-
- -
-
- -
-
-
-
-
-

The keys of a dict have to be immutable

-
-
-
-
-
-
-
-

Thus you can not use e.g. a list or a dict as key because they are mutable types -:

- -
-
-
-
-
-
In [13]:
-
-
-
# bad_dict = {['my_list'], 'value'}  # Raises TypeError
-
- -
-
-
- -
-
-
-
-
-

Values can be mutable

- -
-
-
-
-
-
In [14]:
-
-
-
good_dict = {'my key': ['Python', 'is', 'still', 'cool']}
-print(good_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'my key': ['Python', 'is', 'still', 'cool']}
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/exceptions.html b/notebooks/beginner/html/exceptions.html deleted file mode 100644 index 0e31e35..0000000 --- a/notebooks/beginner/html/exceptions.html +++ /dev/null @@ -1,12025 +0,0 @@ - - - -tmp_exceptions - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Exceptions

When something goes wrong an exception is raised. For example, if you try to divide by zero, ZeroDivisionError is raised or if you try to access a nonexistent key in a dictionary, KeyError is raised.

- -
-
-
-
-
-
In [1]:
-
-
-
empty_dict = {}
-# empty_dict['key']  # Uncomment to see the traceback
-
- -
-
-
- -
-
-
-
-
-

try-except structure

If you know that a block of code can fail in some manner, you can use try-except structure to handle potential exceptions in a desired way.

- -
-
-
-
-
-
In [2]:
-
-
-
# Let's try to open a file that does not exist
-file_name = 'not_existing.txt'
-
-try:
-    with open(file_name, 'r') as my_file:
-        print('File is successfully open')
-        
-except FileNotFoundError as e:
-    print('Uups, file: {} not found'.format(file_name))
-    print('Exception: {} was raised'.format(e))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Uups, file: not_existing.txt not found
-Exception: [Errno 2] No such file or directory: 'not_existing.txt' was raised
-
-
-
- -
-
- -
-
-
-
-
-

If you don't know the type of exceptions that a code block can possibly raise, you can use Exception which catches all exceptions. In addition, you can have multiple except statements.

- -
-
-
-
-
-
In [3]:
-
-
-
def calculate_division(var1, var2):
-    result = 0
-    
-    try:
-        result = var1 / var2
-    except ZeroDivisionError as ex1:
-        print("Can't divide by zero")
-    except Exception as ex2:
-        print('Exception: {}'.format(ex2))
-
-    return result
-
-result1 = calculate_division(3, 3)
-print('result1: {}'.format(result1))
-
-result2 = calculate_division(3, '3')
-print('result2: {}'.format(result2))
-
-result3 = calculate_division(3, 0)
-print('result3: {}'.format(result3))
-
- -
-
-
- -
-
- - -
- -
- - -
-
result1: 1.0
-Exception: unsupported operand type(s) for /: 'int' and 'str'
-result2: 0
-Can't divide by zero
-result3: 0
-
-
-
- -
-
- -
-
-
-
-
-

try-except can be also in outer scope:

- -
-
-
-
-
-
In [4]:
-
-
-
def calculate_division(var1, var2):
-    return var1 / var2
-
-try:
-    result = calculate_division(3, '3')
-except Exception as e:
-    print(e)
-
- -
-
-
- -
-
- - -
- -
- - -
-
unsupported operand type(s) for /: 'int' and 'str'
-
-
-
- -
-
- -
-
-
-
-
-

Creating your custom exceptions

In your own applications, you can use custom exceptions for signaling users about errors which occur during your application run time.

- -
-
-
-
-
-
In [5]:
-
-
-
import math
-
-# Define your own exception
-class NegativeNumbersNotSupported(Exception):
-    pass
-
-# Dummy example how to use your custom exception
-def secret_calculation(number1, number2):
-    if number1 < 0 or number2 < 0:
-        msg = 'Negative number in at least one of the parameters: {}, {}'.format(
-            number1, number2)
-        raise NegativeNumbersNotSupported(msg)
-
-    return math.sqrt(number1) + math.sqrt(number2)
-
-# Uncomment to see the traceback
-# result = secret_calculation(-1, 1)
-
- -
-
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/file_io.html b/notebooks/beginner/html/file_io.html deleted file mode 100644 index 5cb4038..0000000 --- a/notebooks/beginner/html/file_io.html +++ /dev/null @@ -1,12053 +0,0 @@ - - - -tmp_file_io - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

File I/O

Reading and writing files.

- -
-
-
-
-
-
-
-

Working with paths

-
-
-
-
-
-
In [1]:
-
-
-
import os
-
-current_file = os.path.realpath('file_io.ipynb')  
-print('current file: {}'.format(current_file))
-# Note: in .py files you can get the path of current file by __file__
-
-current_dir = os.path.dirname(current_file)  
-print('current directory: {}'.format(current_dir))
-# Note: in .py files you can get the dir of current file by os.path.dirname(__file__)
-
-data_dir = os.path.join(os.path.dirname(current_dir), 'data')
-print('data directory: {}'.format(data_dir))
-
- -
-
-
- -
-
- - -
- -
- - -
-
current file: /Users/jerry/github/jerry-git/learn-python3/notebooks/beginner/notebooks/file_io.ipynb
-current directory: /Users/jerry/github/jerry-git/learn-python3/notebooks/beginner/notebooks
-data directory: /Users/jerry/github/jerry-git/learn-python3/notebooks/beginner/data
-
-
-
- -
-
- -
-
-
-
-
-

Checking if path exists

-
-
-
-
-
-
In [2]:
-
-
-
print('exists: {}'.format(os.path.exists(data_dir)))
-print('is file: {}'.format(os.path.isfile(data_dir)))
-print('is directory: {}'.format(os.path.isdir(data_dir)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
exists: True
-is file: False
-is directory: True
-
-
-
- -
-
- -
-
-
-
-
-

Reading files

-
-
-
-
-
-
In [3]:
-
-
-
file_path = os.path.join(data_dir, 'simple_file.txt')
-
-with open(file_path, 'r') as simple_file:
-    for line in simple_file:
-        print(line.strip())
-
- -
-
-
- -
-
- - -
- -
- - -
-
First line
-Second line
-Third
-And so the story goes!
-
-
-
- -
-
- -
-
-
-
-
-

The with statement is for obtaining a context manager that will be used as an execution context for the commands inside the with. Context managers guarantee that certain operations are done when exiting the context.

-

In this case, the context manager guarantees that simple_file.close() is implicitly called when exiting the context. This is a way to make developers life easier: you don't have to remember to explicitly close the file you openened nor be worried about an exception occuring while the file is open. Unclosed file maybe a source of a resource leak. Thus, prefer using with open() structure always with file I/O.

-

To have an example, the same as above without the with.

- -
-
-
-
-
-
In [4]:
-
-
-
file_path = os.path.join(data_dir, 'simple_file.txt')
-
-# THIS IS NOT THE PREFERRED WAY
-simple_file = open(file_path, 'r')
-for line in simple_file:
-    print(line.strip())
-simple_file.close()  # This has to be called explicitly 
-
- -
-
-
- -
-
- - -
- -
- - -
-
First line
-Second line
-Third
-And so the story goes!
-
-
-
- -
-
- -
-
-
-
-
-

Writing files

-
-
-
-
-
-
In [5]:
-
-
-
new_file_path = os.path.join(data_dir, 'new_file.txt')
-
-with open(new_file_path, 'w') as my_file:
-    my_file.write('This is my first file that I wrote with Python.')
-
- -
-
-
- -
-
-
-
-
-

Now go and check that there is a new_file.txt in the data directory. After that you can delete the file by:

- -
-
-
-
-
-
In [6]:
-
-
-
if os.path.exists(new_file_path):  # make sure it's there
-    os.remove(new_file_path)
-
- -
-
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/for_loops.html b/notebooks/beginner/html/for_loops.html deleted file mode 100644 index 75fbacb..0000000 --- a/notebooks/beginner/html/for_loops.html +++ /dev/null @@ -1,12192 +0,0 @@ - - - -tmp_for_loops - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
- -
-
-
-
-
-
-

Looping lists

-
-
-
-
-
-
In [1]:
-
-
-
my_list = [1, 2, 3, 4, 'Python', 'is', 'neat']
-for item in my_list:
-    print(item)
-
- -
-
-
- -
-
- - -
- -
- - -
-
1
-2
-3
-4
-Python
-is
-neat
-
-
-
- -
-
- -
-
-
-
-
-

break

Stop the execution of the loop.

- -
-
-
-
-
-
In [2]:
-
-
-
for item in my_list:
-    if item == 'Python':
-        break
-    print(item)
-
- -
-
-
- -
-
- - -
- -
- - -
-
1
-2
-3
-4
-
-
-
- -
-
- -
-
-
-
-
-

continue

Continue to the next item without executing the lines occuring after continue inside the loop.

- -
-
-
-
-
-
In [3]:
-
-
-
for item in my_list:
-    if item == 1:
-        continue
-    print(item)
-
- -
-
-
- -
-
- - -
- -
- - -
-
2
-3
-4
-Python
-is
-neat
-
-
-
- -
-
- -
-
-
-
-
-

enumerate()

In case you need to also know the index:

- -
-
-
-
-
-
In [4]:
-
-
-
for idx, val in enumerate(my_list):
-    print('idx: {}, value: {}'.format(idx, val))
-
- -
-
-
- -
-
- - -
- -
- - -
-
idx: 0, value: 1
-idx: 1, value: 2
-idx: 2, value: 3
-idx: 3, value: 4
-idx: 4, value: Python
-idx: 5, value: is
-idx: 6, value: neat
-
-
-
- -
-
- -
-
-
-
-
-

Looping dictionaries

-
-
-
-
-
-
In [5]:
-
-
-
my_dict = {'hacker': True, 'age': 72, 'name': 'John Doe'}
-for val in my_dict:
-    print(val)
-
- -
-
-
- -
-
- - -
- -
- - -
-
age
-name
-hacker
-
-
-
- -
-
- -
-
-
-
In [6]:
-
-
-
for key, val in my_dict.items():
-    print('{}={}'.format(key, val))
-
- -
-
-
- -
-
- - -
- -
- - -
-
age=72
-name=John Doe
-hacker=True
-
-
-
- -
-
- -
-
-
-
-
-

range()

-
-
-
-
-
-
In [7]:
-
-
-
for number in range(5):
-    print(number)
-
- -
-
-
- -
-
- - -
- -
- - -
-
0
-1
-2
-3
-4
-
-
-
- -
-
- -
-
-
-
In [8]:
-
-
-
for number in range(2, 5):
-    print(number)
-
- -
-
-
- -
-
- - -
- -
- - -
-
2
-3
-4
-
-
-
- -
-
- -
-
-
-
In [9]:
-
-
-
for number in range(0, 10, 2):  # last one is step
-    print(number)
-
- -
-
-
- -
-
- - -
- -
- - -
-
0
-2
-4
-6
-8
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/functions.html b/notebooks/beginner/html/functions.html deleted file mode 100644 index a746d44..0000000 --- a/notebooks/beginner/html/functions.html +++ /dev/null @@ -1,12274 +0,0 @@ - - - -tmp_functions - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Functions

-
-
-
-
-
-
In [1]:
-
-
-
def my_first_function():
-    print('Hello world!')
-
-print('type: {}'.format(my_first_function))
-
-my_first_function()  # Calling a function
-
- -
-
-
- -
-
- - -
- -
- - -
-
type: <function my_first_function at 0x1068d98c8>
-Hello world!
-
-
-
- -
-
- -
-
-
-
-
-

Arguments

-
-
-
-
-
-
In [2]:
-
-
-
def greet_us(name1, name2):
-    print('Hello {} and {}!'.format(name1, name2))
-
-greet_us('John Doe', 'Superman')
-
- -
-
-
- -
-
- - -
- -
- - -
-
Hello John Doe and Superman!
-
-
-
- -
-
- -
-
-
-
In [3]:
-
-
-
# Function with return value
-def strip_and_lowercase(original):
-    modified = original.strip().lower()
-    return modified
-
-uggly_string = '  MixED CaSe '
-pretty = strip_and_lowercase(uggly_string)
-print('pretty: {}'.format(pretty))
-
- -
-
-
- -
-
- - -
- -
- - -
-
pretty: mixed case
-
-
-
- -
-
- -
-
-
-
-
-

Keyword arguments

-
-
-
-
-
-
In [4]:
-
-
-
def my_fancy_calculation(first, second, third):
-    return first + second - third 
-
-print(my_fancy_calculation(3, 2, 1))
-
-print(my_fancy_calculation(first=3, second=2, third=1))
-
-# With keyword arguments you can mix the order
-print(my_fancy_calculation(third=1, first=3, second=2))
-
-# You can mix arguments and keyword arguments but you have to start with arguments
-print(my_fancy_calculation(3, third=1, second=2))  
-
- -
-
-
- -
-
- - -
- -
- - -
-
4
-4
-4
-4
-
-
-
- -
-
- -
-
-
-
-
-

Default arguments

-
-
-
-
-
-
In [5]:
-
-
-
def create_person_info(name, age, job=None, salary=300):
-    info = {'name': name, 'age': age, 'salary': salary}
-    
-    # Add 'job' key only if it's provided as parameter
-    if job:  
-        info.update(dict(job=job))
-        
-    return info
-
-person1 = create_person_info('John Doe', 82)  # use default values for job and salary
-person2 = create_person_info('Lisa Doe', 22, 'hacker', 10000)
-print(person1)
-print(person2)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'name': 'John Doe', 'age': 82, 'salary': 300}
-{'name': 'Lisa Doe', 'age': 22, 'salary': 10000, 'job': 'hacker'}
-
-
-
- -
-
- -
-
-
-
-
-

Don't use mutable objects as default arguments!

- -
-
-
-
-
-
In [6]:
-
-
-
def append_if_multiple_of_five(number, magical_list=[]):
-    if number % 5 == 0:
-        magical_list.append(number)
-    return magical_list
-
-print(append_if_multiple_of_five(100))
-print(append_if_multiple_of_five(105))
-print(append_if_multiple_of_five(123))
-print(append_if_multiple_of_five(123, []))
-print(append_if_multiple_of_five(123))
-
- -
-
-
- -
-
- - -
- -
- - -
-
[100]
-[100, 105]
-[100, 105]
-[]
-[100, 105]
-
-
-
- -
-
- -
-
-
-
-
-

Here's how you can achieve desired behavior:

- -
-
-
-
-
-
In [7]:
-
-
-
def append_if_multiple_of_five(number, magical_list=None):
-    if not magical_list:
-        magical_list = []
-    if number % 5 == 0:
-        magical_list.append(number)
-    return magical_list
-
-print(append_if_multiple_of_five(100))
-print(append_if_multiple_of_five(105))
-print(append_if_multiple_of_five(123))
-print(append_if_multiple_of_five(123, []))
-print(append_if_multiple_of_five(123))
-
- -
-
-
- -
-
- - -
- -
- - -
-
[100]
-[105]
-[]
-[]
-[]
-
-
-
- -
-
- -
-
-
-
-
-

Docstrings

Strings for documenting your functions, methods, modules and variables.

- -
-
-
-
-
-
In [8]:
-
-
-
def print_sum(val1, val2):
-    """Function which prints the sum of given arguments."""
-    print('sum: {}'.format(val1 + val2))
-
-print(help(print_sum))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Help on function print_sum in module __main__:
-
-print_sum(val1, val2)
-    Function which prints the sum of given arguments.
-
-None
-
-
-
- -
-
- -
-
-
-
In [9]:
-
-
-
def calculate_sum(val1, val2):
-    """This is a longer docstring defining also the args and the return value. 
-
-    Args:
-        val1: The first parameter.
-        val2: The second parameter.
-
-    Returns:
-        The sum of val1 and val2.
-        
-    """
-    return val1 + val2
-
-print(help(calculate_sum))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Help on function calculate_sum in module __main__:
-
-calculate_sum(val1, val2)
-    This is a longer docstring defining also the args and the return value. 
-    
-    Args:
-        val1: The first parameter.
-        val2: The second parameter.
-    
-    Returns:
-        The sum of val1 and val2.
-
-None
-
-
-
- -
-
- -
-
-
-
-
-

pass statement

pass is a statement which does nothing when it's executed. It can be used e.g. a as placeholder to make the code syntatically correct while sketching the functions and/or classes of your application. For example, the following is valid Python.

- -
-
-
-
-
-
In [10]:
-
-
-
def my_function(some_argument):
-    pass
-
-def my_other_function():
-    pass
-
- -
-
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/lists.html b/notebooks/beginner/html/lists.html deleted file mode 100644 index e5603d9..0000000 --- a/notebooks/beginner/html/lists.html +++ /dev/null @@ -1,12472 +0,0 @@ - - - -tmp_lists - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
- -
-
-
-
-
In [1]:
-
-
-
my_empty_list = []
-print('empty list: {}, type: {}'.format(my_empty_list, type(my_empty_list)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
empty list: [], type: <class 'list'>
-
-
-
- -
-
- -
-
-
-
In [2]:
-
-
-
list_of_ints = [1, 2, 6, 7]
-list_of_misc = [0.2, 5, 'Python', 'is', 'still fun', '!']
-print('lengths: {} and {}'.format(len(list_of_ints), len(list_of_misc)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
lengths: 4 and 6
-
-
-
- -
-
- -
-
-
-
-
-

Accessing values

-
-
-
-
-
-
In [3]:
-
-
-
my_list = ['Python', 'is', 'still', 'cool']
-print(my_list[0])
-print(my_list[3])
-
- -
-
-
- -
-
- - -
- -
- - -
-
Python
-cool
-
-
-
- -
-
- -
-
-
-
In [4]:
-
-
-
coordinates = [[12.0, 13.3], [0.6, 18.0], [88.0, 1.1]]  # two dimensional
-print('first coordinate: {}'.format(coordinates[0]))
-print('second element of first coordinate: {}'.format(coordinates[0][1]))
-
- -
-
-
- -
-
- - -
- -
- - -
-
first coordinate: [12.0, 13.3]
-second element of first coordinate: 13.3
-
-
-
- -
-
- -
-
-
-
-
-

Updating values

-
-
-
-
-
-
In [5]:
-
-
-
my_list = [0, 1, 2, 3, 4, 5]
-my_list[0] = 99
-print(my_list)
-
-# remove first value
-del my_list[0]
-print(my_list)
-
- -
-
-
- -
-
- - -
- -
- - -
-
[99, 1, 2, 3, 4, 5]
-[1, 2, 3, 4, 5]
-
-
-
- -
-
- -
-
-
-
-
-

Checking if certain value is present in list

-
-
-
-
-
-
In [6]:
-
-
-
languages = ['Java', 'C++', 'Go', 'Python', 'JavaScript']
-if 'Python' in languages:
-    print('Python is there!')
-
- -
-
-
- -
-
- - -
- -
- - -
-
Python is there!
-
-
-
- -
-
- -
-
-
-
In [7]:
-
-
-
if 6 not in [1, 2, 3, 7]:
-    print('number 6 is not present')
-
- -
-
-
- -
-
- - -
- -
- - -
-
number 6 is not present
-
-
-
- -
-
- -
-
-
-
-
-

List are mutable

-
-
-
-
-
-
In [8]:
-
-
-
original = [1, 2, 3]
-modified = original
-modified[0] = 99
-print('original: {}, modified: {}'.format(original, modified))
-
- -
-
-
- -
-
- - -
- -
- - -
-
original: [99, 2, 3], modified: [99, 2, 3]
-
-
-
- -
-
- -
-
-
-
-
-

You can get around this by creating new list:

- -
-
-
-
-
-
In [9]:
-
-
-
original = [1, 2, 3]
-modified = list(original)  # Note list() 
-# Alternatively, you can use copy method
-# modified = original.copy()
-modified[0] = 99
-print('original: {}, modified: {}'.format(original, modified))
-
- -
-
-
- -
-
- - -
- -
- - -
-
original: [1, 2, 3], modified: [99, 2, 3]
-
-
-
- -
-
- -
-
-
-
-
-

list.append()

-
-
-
-
-
-
In [10]:
-
-
-
my_list = [1]
-my_list.append('ham')
-print(my_list)
-
- -
-
-
- -
-
- - -
- -
- - -
-
[1, 'ham']
-
-
-
- -
-
- -
-
-
-
-
-

list.remove()

-
-
-
-
-
-
In [11]:
-
-
-
my_list = ['Python', 'is', 'sometimes', 'fun']
-my_list.remove('sometimes')
-print(my_list)
-
-# If you are not sure that the value is in list, better to check first:
-if 'Java' in my_list:
-    my_list.remove('Java')
-else:
-    print('Java is not part of this story.')
-
- -
-
-
- -
-
- - -
- -
- - -
-
['Python', 'is', 'fun']
-Java is not part of this story.
-
-
-
- -
-
- -
-
-
-
-
-

list.sort()

-
-
-
-
-
-
In [12]:
-
-
-
numbers = [8, 1, 6, 5, 10]
-numbers.sort()
-print('numbers: {}'.format(numbers))
-
-numbers.sort(reverse=True)
-print('numbers reversed: {}'.format(numbers))
-
-words = ['this', 'is', 'a', 'list', 'of', 'words']
-words.sort()
-print('words: {}'.format(words))
-
- -
-
-
- -
-
- - -
- -
- - -
-
numbers: [1, 5, 6, 8, 10]
-numbers reversed: [10, 8, 6, 5, 1]
-words: ['a', 'is', 'list', 'of', 'this', 'words']
-
-
-
- -
-
- -
-
-
-
-
-

sorted(list)

While list.sort() sorts the list in-place, sorted(list) returns a new list and leaves the original untouched:

- -
-
-
-
-
-
In [13]:
-
-
-
numbers = [8, 1, 6, 5, 10]
-sorted_numbers = sorted(numbers)
-print('numbers: {}, sorted: {}'.format(numbers, sorted_numbers))
-
- -
-
-
- -
-
- - -
- -
- - -
-
numbers: [8, 1, 6, 5, 10], sorted: [1, 5, 6, 8, 10]
-
-
-
- -
-
- -
-
-
-
-
-

list.extend()

-
-
-
-
-
-
In [14]:
-
-
-
first_list = ['beef', 'ham']
-second_list = ['potatoes',1 ,3]
-first_list.extend(second_list)
-print('first: {}, second: {}'.format(first_list, second_list))
-
- -
-
-
- -
-
- - -
- -
- - -
-
first: ['beef', 'ham', 'potatoes', 1, 3], second: ['potatoes', 1, 3]
-
-
-
- -
-
- -
-
-
-
-
-

Alternatively you can also extend lists by summing them:

- -
-
-
-
-
-
In [15]:
-
-
-
first = [1, 2, 3]
-second = [4, 5]
-first += second  # same as: first = first + second
-print('first: {}'.format(first))
-
-# If you need a new list
-summed = first + second
-print('summed: {}'.format(summed))
-
- -
-
-
- -
-
- - -
- -
- - -
-
first: [1, 2, 3, 4, 5]
-summed: [1, 2, 3, 4, 5, 4, 5]
-
-
-
- -
-
- -
-
-
-
-
-

list.reverse()

-
-
-
-
-
-
In [16]:
-
-
-
my_list = ['a', 'b', 'ham']
-my_list.reverse()
-print(my_list)
-
- -
-
-
- -
-
- - -
- -
- - -
-
['ham', 'b', 'a']
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/modules_and_packages.html b/notebooks/beginner/html/modules_and_packages.html deleted file mode 100644 index 9c4674b..0000000 --- a/notebooks/beginner/html/modules_and_packages.html +++ /dev/null @@ -1,11903 +0,0 @@ - - - -tmp_modules_and_packages - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Modules and packages

Module is a Python source code file, i.e. a file with .py extension.

-

Package is a directory which contains __init__.py file and can contain python modules and other packages.

-
- -
-
-
-
-
-
-
-

Why to organize your code into modules and packages

    -
  • Maintainability
  • -
  • Reusability
  • -
  • Namespacing
  • -
  • People unfamiliar with your project can get a clear overview just by looking at the directory structure of your project
  • -
  • Searching for certain functionality or class is easy
  • -
- -
-
-
-
-
-
-
-

How to use

Let's use the following directory structure as an example:

- -
food_store/
-    __init__.py
-
-    product/
-        __init__.py
-
-        fruit/
-            __init__.py
-            apple.py
-            banana.py
-
-        drink/
-            __init__.py
-            juice.py
-            milk.py
-            beer.py
-
-    cashier/
-        __ini__.py
-        receipt.py
-        calculator.py
-

Let's consider that banana.py file contains:

-
def get_available_brands():
-    return ['chiquita']
-
-
-class Banana:
-    def __init__(self, brand='chiquita'):
-        if brand not in get_available_brands():
-            raise ValueError('Unkown brand: {}'.format(brand))
-        self._brand = brand
-
- -
-
-
-
-
-
-
-

Importing

Let's say that we need access Banana class from banana.py file inside receipt.py. We can achive this by importing at the beginning of receipt.py:

-
from food_store.product.fruit.banana import Banana
-
-# then it's used like this
-my_banana = Banana()
-
-

If we need to access multiple classes or functions from banana.py file:

-
from food_store.product.fruit import banana
-
-# then it's used like this
-brands = banana.get_available_brands()
-my_banana = banana.Banana()
-
- -
-
-
-
-
-
-
-

A comprehensive introduction to modules and packages can be found here.

- -
-
-
-
-
- - - - - - diff --git a/notebooks/beginner/html/numbers.html b/notebooks/beginner/html/numbers.html deleted file mode 100644 index 3572b15..0000000 --- a/notebooks/beginner/html/numbers.html +++ /dev/null @@ -1,12216 +0,0 @@ - - - -tmp_numbers - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
- -
-
-
-
-
-
-

int

-
-
-
-
-
-
In [1]:
-
-
-
my_int = 6
-print('value: {}, type: {}'.format(my_int, type(my_int)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
value: 6, type: <class 'int'>
-
-
-
- -
-
- -
-
-
-
-
-

float

-
-
-
-
-
-
In [2]:
-
-
-
my_float = float(my_int)
-print('value: {}, type: {}'.format(my_float, type(my_float)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
value: 6.0, type: <class 'float'>
-
-
-
- -
-
- -
-
-
-
-
-

Note that division of ints produces float:

- -
-
-
-
-
-
In [3]:
-
-
-
print(1 / 1)
-print(6 / 5)
-
- -
-
-
- -
-
- - -
- -
- - -
-
1.0
-1.2
-
-
-
- -
-
- -
-
-
-
-
-

Be aware of the binary floating-point pitfalls (see Decimal for workaround):

- -
-
-
-
-
-
In [4]:
-
-
-
val = 0.1 + 0.1 + 0.1
-print(val == 0.3)
-print(val)
-
- -
-
-
- -
-
- - -
- -
- - -
-
False
-0.30000000000000004
-
-
-
- -
-
- -
-
-
-
-
-

Floor division //, modulus %, power **

-
-
-
-
-
-
In [5]:
-
-
-
7 // 5
-
- -
-
-
- -
-
- - -
- -
Out[5]:
- - - - -
-
1
-
- -
- -
-
- -
-
-
-
In [6]:
-
-
-
7 % 5
-
- -
-
-
- -
-
- - -
- -
Out[6]:
- - - - -
-
2
-
- -
- -
-
- -
-
-
-
In [7]:
-
-
-
2 ** 3
-
- -
-
-
- -
-
- - -
- -
Out[7]:
- - - - -
-
8
-
- -
- -
-
- -
-
-
- -
-
-
-
In [8]:
-
-
-
from decimal import Decimal
-
- -
-
-
- -
-
-
-
In [9]:
-
-
-
from_float = Decimal(0.1)
-from_str = Decimal('0.1')
-print('from float: {}\nfrom string: {}'.format(from_float, from_str))
-
- -
-
-
- -
-
- - -
- -
- - -
-
from float: 0.1000000000000000055511151231257827021181583404541015625
-from string: 0.1
-
-
-
- -
-
- -
-
-
-
In [10]:
-
-
-
my_decimal = Decimal('0.1')
-sum_of_decimals = my_decimal + my_decimal + my_decimal
-print(sum_of_decimals == Decimal('0.3'))
-
- -
-
-
- -
-
- - -
- -
- - -
-
True
-
-
-
- -
-
- -
-
-
-
-
-

Operator precedence in calculations

Mathematical operator precedence applies. Use brackets if you want to change the execution order:

- -
-
-
-
-
-
In [11]:
-
-
-
print(1 + 2**2 * 3 / 6) # 1 + 4 * 3 / 6 == 1 + 12 / 6 == 1 + 2
-print((1 + 2**2) * 3 / 6)
-
- -
-
-
- -
-
- - -
- -
- - -
-
3.0
-2.5
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/project_structure.html b/notebooks/beginner/html/project_structure.html deleted file mode 100644 index a634496..0000000 --- a/notebooks/beginner/html/project_structure.html +++ /dev/null @@ -1,11925 +0,0 @@ - - - -tmp_project_structure - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Project structure

-
-
-
-
-
-
-
-

Python script

Python is a great language for building small helper tools for various different kinds of tasks. Such small tools can be often expressed as a single file Python script.

-

Here is an example structure for a Python script (aka executable Python module).

- -
-
-
-
-
-
In [1]:
-
-
-
# the content of my_script.py
-
-# imports
-import logging
-
-# constants
-LOGGER = logging.getLogger()
-
-
-def magical_function():
-    LOGGER.warning('We are about to do some magical stuff')
-
-
-def main():
-    # The actual logic of the script
-    magical_function()
-
-
-if __name__ == '__main__':
-    main()
-
- -
-
-
- -
-
- - -
- -
- - -
-
We are about to do some magical stuff
-
-
-
- -
-
- -
-
-
-
-
-

Python package

An example structure for a python project:

- -
my_project/
-    README.md
-    requirements.txt
-    setup.py
-
-    src/
-        my_project/
-            __init__.py
-            my_module.py
-            other_module.py
-
-            my_pkg1/
-                __init__.py
-                my_third_module.py
-
-    tests/
-        conftest.py
-        test_module.py
-        test_other_module.py
-
-        my_pkg1/
-            test_my_third_module.py
-
    -
  • requirements.txt lists the Python packages from which my_project depends on.
      -
    • these can be installed by running pip install -r requirements
    • -
    -
  • -
  • setup.py is a file in which you include relevant information about your project and the file is also used for packaging your project. Here's a minimal example of a setup.py:
  • -
-
'''Minimal setup.py file'''
-
-from setuptools import setup, find_packages
-
-setup(
-    name='my_project',
-    version='0.1',
-    packages=find_packages(where="src"),
-    package_dir={"": "src"})
-
-
    -
  • Once you have the setup.py file in place, you can install your project in editable mode by running pip install -e . in the root directory of your project. In editable mode the installed version is updated when you make changes to the source code files.
  • -
- -
-
-
-
-
- - - - - - diff --git a/notebooks/beginner/html/std_lib.html b/notebooks/beginner/html/std_lib.html deleted file mode 100644 index b6251fe..0000000 --- a/notebooks/beginner/html/std_lib.html +++ /dev/null @@ -1,12517 +0,0 @@ - - - -tmp_std_lib - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Goodies of the Python Standard Library

The Python Standard Libary is part of your Python installation. It contains a wide range of packages which may be helpful while building your Python masterpieces. This notebook lists some of the commonly used packages and their main functionalities.

- -
-
-
-
-
-
-
-

datetime for working with dates and times

-
-
-
-
-
-
In [1]:
-
-
-
import datetime as dt
-
-local_now = dt.datetime.now()
-print('local now: {}'.format(local_now))
-
-utc_now = dt.datetime.utcnow()
-print('utc now: {}'.format(utc_now))
-
-# You can access any value separately:
-print('{} {} {} {} {} {}'.format(local_now.year, local_now.month,
-                                 local_now.day, local_now.hour,
-                                 local_now.minute, local_now.second))
-
-print('date: {}'.format(local_now.date()))
-print('time: {}'.format(local_now.time()))
-
- -
-
-
- -
-
- - -
- -
- - -
-
local now: 2018-09-19 22:44:15.396930
-utc now: 2018-09-19 20:44:15.397085
-2018 9 19 22 44 15
-date: 2018-09-19
-time: 22:44:15.396930
-
-
-
- -
-
- -
-
-
-
-
-

strftime()

For string formatting the datetime

- -
-
-
-
-
-
In [2]:
-
-
-
formatted1 = local_now.strftime('%Y/%m/%d-%H:%M:%S')
-print(formatted1)
-
-formatted2 = local_now.strftime('date: %Y-%m-%d time:%H:%M:%S')
-print(formatted2)
-
- -
-
-
- -
-
- - -
- -
- - -
-
2018/09/19-22:44:15
-date: 2018-09-19 time:22:44:15
-
-
-
- -
-
- -
-
-
-
-
-

strptime()

For converting a datetime string into a datetime object

- -
-
-
-
-
-
In [3]:
-
-
-
my_dt = dt.datetime.strptime('2000-01-01 10:00:00', '%Y-%m-%d %H:%M:%S')
-print('my_dt: {}'.format(my_dt))
-
- -
-
-
- -
-
- - -
- -
- - -
-
my_dt: 2000-01-01 10:00:00
-
-
-
- -
-
- -
-
-
-
-
-

timedelta

For working with time difference.

- -
-
-
-
-
-
In [4]:
-
-
-
tomorrow = local_now + dt.timedelta(days=1)
-print('tomorrow this time: {}'.format(tomorrow))
-
-delta = tomorrow - local_now
-print('tomorrow - now = {}'.format(delta))
-print('days: {}, seconds: {}'.format(delta.days, delta.seconds))
-print('total seconds: {}'.format(delta.total_seconds()))
-
- -
-
-
- -
-
- - -
- -
- - -
-
tomorrow this time: 2018-09-20 22:44:15.396930
-tomorrow - now = 1 day, 0:00:00
-days: 1, seconds: 0
-total seconds: 86400.0
-
-
-
- -
-
- -
-
-
-
-
-

Working with timezones

Let's first make sure pytz is installed.

- -
-
-
-
-
-
In [5]:
-
-
-
import sys
-!{sys.executable} -m pip install pytz
-
- -
-
-
- -
-
- - -
- -
- - -
-
Requirement already satisfied: pytz in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (2018.4)
-
-
-
- -
-
- -
-
-
-
In [6]:
-
-
-
import datetime as dt
-import pytz
-
-naive_utc_now = dt.datetime.utcnow()
-print('naive utc now: {}, tzinfo: {}'.format(naive_utc_now, naive_utc_now.tzinfo))
-
-# Localizing naive datetimes
-UTC_TZ = pytz.timezone('UTC')
-utc_now = UTC_TZ.localize(naive_utc_now)
-print('utc now: {}, tzinfo: {}'.format(utc_now, utc_now.tzinfo))
-
-# Converting localized datetimes to different timezone
-PARIS_TZ = pytz.timezone('Europe/Paris')
-paris_now = PARIS_TZ.normalize(utc_now)
-print('Paris: {}, tzinfo: {}'.format(paris_now, paris_now.tzinfo))
-
-NEW_YORK_TZ = pytz.timezone('America/New_York')
-ny_now = NEW_YORK_TZ.normalize(utc_now)
-print('New York: {}, tzinfo: {}'.format(ny_now, ny_now.tzinfo))
-
- -
-
-
- -
-
- - -
- -
- - -
-
naive utc now: 2018-09-19 20:44:16.308229, tzinfo: None
-utc now: 2018-09-19 20:44:16.308229+00:00, tzinfo: UTC
-Paris: 2018-09-19 22:44:16.308229+02:00, tzinfo: Europe/Paris
-New York: 2018-09-19 16:44:16.308229-04:00, tzinfo: America/New_York
-
-
-
- -
-
- -
-
-
-
-
-

NOTE: If your project uses datetimes heavily, you may want to take a look at external libraries, such as Pendulum and Maya, which make working with datetimes easier for certain use cases.

- -
-
-
-
-
-
- -
-
-
-
-
In [7]:
-
-
-
import logging
-
-# Handy way for getting a dedicated logger for every module separately
-logger = logging.getLogger(__name__)
-logger.setLevel(logging.WARNING)
-
-logger.debug('This is debug')
-logger.info('This is info')
-logger.warning('This is warning')
-logger.error('This is error')
-logger.critical('This is critical')
-
- -
-
-
- -
-
- - -
- -
- - -
-
This is warning
-This is error
-This is critical
-
-
-
- -
-
- -
-
-
-
-
-

Logging expections

There's a neat exception function in logging module which will automatically log the stack trace in addition to user defined log entry.

- -
-
-
-
-
-
In [8]:
-
-
-
try:
-    path_calculation = 1 / 0
-except ZeroDivisionError:
-    logging.exception('All went south in my calculation')
-
- -
-
-
- -
-
- - -
- -
- - -
-
ERROR:root:All went south in my calculation
-Traceback (most recent call last):
-  File "<ipython-input-8-ccd7d25e79b7>", line 2, in <module>
-    path_calculation = 1 / 0
-ZeroDivisionError: division by zero
-
-
-
- -
-
- -
-
-
-
-
-

Formatting log entries

-
-
-
-
-
-
In [9]:
-
-
-
import logging
-
-# This is only required for Jupyter notebook environment
-from importlib import reload
-reload(logging)
-
-my_format = '%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s'
-logging.basicConfig(format=my_format)
-
-logger = logging.getLogger('MyLogger')
-
-logger.warning('Something bad is going to happen')
-logger.error('Uups, it already happened')
-
- -
-
-
- -
-
- - -
- -
- - -
-
2018-09-19 22:44:16,365 | MyLogger     | WARNING    | Something bad is going to happen
-2018-09-19 22:44:16,366 | MyLogger     | ERROR      | Uups, it already happened
-
-
-
- -
-
- -
-
-
-
-
-

Logging to a file

-
-
-
-
-
-
In [10]:
-
-
-
import os
-import logging
-
-# This is only required for Jupyter notebook environment
-from importlib import reload
-reload(logging)
-
-logger = logging.getLogger('MyFileLogger')
-
-# Let's define a file_handler for our logger
-log_path = os.path.join(os.getcwd(), 'my_log.txt')
-file_handler = logging.FileHandler(log_path)
-
-# And a nice format
-formatter = logging.Formatter('%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s')
-file_handler.setFormatter(formatter)
-
-logger.addHandler(file_handler)
-
-# If you want to see it also in the console, add another handler for it
-# logger.addHandler(logging.StreamHandler())
-
-logger.warning('Oops something is going to happen')
-logger.error('John Doe visits our place')
-
- -
-
-
- -
-
-
-
-
-

random for random number generation

-
-
-
-
-
-
In [11]:
-
-
-
import random
-
-rand_int = random.randint(1, 100)
-print('random integer between 1-100: {}'.format(rand_int))
-
-rand = random.random()
-print('random float between 0-1: {}'.format(rand))
-
- -
-
-
- -
-
- - -
- -
- - -
-
random integer between 1-100: 33
-random float between 0-1: 0.10137384902353497
-
-
-
- -
-
- -
-
-
-
-
-

If you need pseudo random numbers, you can set the seed for random. This will reproduce the output (try running the cell multiple times):

- -
-
-
-
-
-
In [12]:
-
-
-
import random
-
-random.seed(5)  # Setting the seed
-
-# Let's print 10 random numbers
-for _ in range(10):
-    print(random.random())
-
- -
-
-
- -
-
- - -
- -
- - -
-
0.6229016948897019
-0.7417869892607294
-0.7951935655656966
-0.9424502837770503
-0.7398985747399307
-0.922324996665417
-0.029005228283614737
-0.46562265437810535
-0.9433567169983137
-0.6489745531369242
-
-
-
- -
-
- -
-
-
-
-
-

re for regular expressions

-
-
-
-
-
-
-
-

Searching occurences

-
-
-
-
-
-
In [13]:
-
-
-
import re
-
-secret_code = 'qwret 8sfg12f5 fd09f_df'
-# "r" at the beginning means raw format, use it with regular expression patterns
-search_pattern = r'(g12)' 
-
-match = re.search(search_pattern, secret_code)
-print('match: {}'.format(match))
-print('match.group(): {}'.format(match.group()))
-
-numbers_pattern = r'[0-9]'
-numbers_match = re.findall(numbers_pattern, secret_code)
-print('numbers: {}'.format(numbers_match))
-
- -
-
-
- -
-
- - -
- -
- - -
-
match: <_sre.SRE_Match object; span=(9, 12), match='g12'>
-match.group(): g12
-numbers: ['8', '1', '2', '5', '0', '9']
-
-
-
- -
-
- -
-
-
-
-
-

Variable validation

-
-
-
-
-
-
In [14]:
-
-
-
import re
-
-def validate_only_lower_case_letters(to_validate):
-    pattern = r'^[a-z]+$'
-    return bool(re.match(pattern, to_validate))
-
-print(validate_only_lower_case_letters('thisshouldbeok'))
-print(validate_only_lower_case_letters('thisshould notbeok'))
-print(validate_only_lower_case_letters('Thisshouldnotbeok'))
-print(validate_only_lower_case_letters('thisshouldnotbeok1'))
-print(validate_only_lower_case_letters(''))
-
- -
-
-
- -
-
- - -
- -
- - -
-
True
-False
-False
-False
-False
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/strings.html b/notebooks/beginner/html/strings.html deleted file mode 100644 index 39d0fe1..0000000 --- a/notebooks/beginner/html/strings.html +++ /dev/null @@ -1,12711 +0,0 @@ - - - -tmp_strings - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
- -
-
-
-
-
In [1]:
-
-
-
my_string = 'Python is my favorite programming language!'
-
- -
-
-
- -
-
-
-
In [2]:
-
-
-
my_string
-
- -
-
-
- -
-
- - -
- -
Out[2]:
- - - - -
-
'Python is my favorite programming language!'
-
- -
- -
-
- -
-
-
-
In [3]:
-
-
-
type(my_string)
-
- -
-
-
- -
-
- - -
- -
Out[3]:
- - - - -
-
str
-
- -
- -
-
- -
-
-
-
In [4]:
-
-
-
len(my_string)
-
- -
-
-
- -
-
- - -
- -
Out[4]:
- - - - -
-
43
-
- -
- -
-
- -
-
-
-
-
-

Respecting PEP8 with long strings

-
-
-
-
-
-
In [5]:
-
-
-
long_story = ('Lorem ipsum dolor sit amet, consectetur adipiscing elit.' 
-              'Pellentesque eget tincidunt felis. Ut ac vestibulum est.' 
-              'In sed ipsum sit amet sapien scelerisque bibendum. Sed ' 
-              'sagittis purus eu diam fermentum pellentesque.')
-long_story
-
- -
-
-
- -
-
- - -
- -
Out[5]:
- - - - -
-
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.Pellentesque eget tincidunt felis. Ut ac vestibulum est.In sed ipsum sit amet sapien scelerisque bibendum. Sed sagittis purus eu diam fermentum pellentesque.'
-
- -
- -
-
- -
-
-
-
-
-

str.replace()

-
-
-
-
-
-
-
-

If you don't know how it works, you can always check the help:

- -
-
-
-
-
-
In [6]:
-
-
-
help(str.replace)
-
- -
-
-
- -
-
- - -
- -
- - -
-
Help on method_descriptor:
-
-replace(...)
-    S.replace(old, new[, count]) -> str
-    
-    Return a copy of S with all occurrences of substring
-    old replaced by new.  If the optional argument count is
-    given, only the first count occurrences are replaced.
-
-
-
-
- -
-
- -
-
-
-
-
-

This will not modify my_string because replace is not done in-place.

- -
-
-
-
-
-
In [7]:
-
-
-
my_string.replace('a', '?')
-print(my_string)
-
- -
-
-
- -
-
- - -
- -
- - -
-
Python is my favorite programming language!
-
-
-
- -
-
- -
-
-
-
-
-

You have to store the return value of replace instead.

- -
-
-
-
-
-
In [8]:
-
-
-
my_modified_string = my_string.replace('is', 'will be')
-print(my_modified_string)
-
- -
-
-
- -
-
- - -
- -
- - -
-
Python will be my favorite programming language!
-
-
-
- -
-
- -
-
-
-
-
-

str.format()

-
-
-
-
-
-
In [9]:
-
-
-
secret = '{} is cool'.format('Python')
-print(secret)
-
- -
-
-
- -
-
- - -
- -
- - -
-
Python is cool
-
-
-
- -
-
- -
-
-
-
In [10]:
-
-
-
print('My name is {} {}, you can call me {}.'.format('John', 'Doe', 'John'))
-# is the same as:
-print('My name is {first} {family}, you can call me {first}.'.format(first='John', family='Doe'))
-
- -
-
-
- -
-
- - -
- -
- - -
-
My name is John Doe, you can call me John.
-My name is John Doe, you can call me John.
-
-
-
- -
-
- -
-
-
-
-
-

str.join()

-
-
-
-
-
-
In [11]:
-
-
-
pandas = 'pandas'
-numpy = 'numpy'
-requests = 'requests'
-cool_python_libs = ', '.join([pandas, numpy, requests])
-
- -
-
-
- -
-
-
-
In [12]:
-
-
-
print('Some cool python libraries: {}'.format(cool_python_libs))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Some cool python libraries: pandas, numpy, requests
-
-
-
- -
-
- -
-
-
-
-
-

Alternatives (not as Pythonic and slower):

- -
-
-
-
-
-
In [13]:
-
-
-
cool_python_libs = pandas + ', ' + numpy + ', ' + requests
-print('Some cool python libraries: {}'.format(cool_python_libs))
-
-cool_python_libs = pandas
-cool_python_libs += ', ' + numpy
-cool_python_libs += ', ' + requests
-print('Some cool python libraries: {}'.format(cool_python_libs))
-
- -
-
-
- -
-
- - -
- -
- - -
-
Some cool python libraries: pandas, numpy, requests
-Some cool python libraries: pandas, numpy, requests
-
-
-
- -
-
- -
-
-
-
-
-

str.upper(), str.lower(), str.title()

-
-
-
-
-
-
In [14]:
-
-
-
mixed_case = 'PyTHoN hackER'
-
- -
-
-
- -
-
-
-
In [15]:
-
-
-
mixed_case.upper()
-
- -
-
-
- -
-
- - -
- -
Out[15]:
- - - - -
-
'PYTHON HACKER'
-
- -
- -
-
- -
-
-
-
In [16]:
-
-
-
mixed_case.lower()
-
- -
-
-
- -
-
- - -
- -
Out[16]:
- - - - -
-
'python hacker'
-
- -
- -
-
- -
-
-
-
In [17]:
-
-
-
mixed_case.title()
-
- -
-
-
- -
-
- - -
- -
Out[17]:
- - - - -
-
'Python Hacker'
-
- -
- -
-
- -
-
-
-
-
-

str.strip()

-
-
-
-
-
-
In [18]:
-
-
-
ugly_formatted = ' \n \t Some story to tell '
-stripped = ugly_formatted.strip()
-
-print('ugly: {}'.format(ugly_formatted))
-print('stripped: {}'.format(ugly_formatted.strip()))
-
- -
-
-
- -
-
- - -
- -
- - -
-
ugly:  
- 	 Some story to tell 
-stripped: Some story to tell
-
-
-
- -
-
- -
-
-
-
-
-

str.split()

-
-
-
-
-
-
In [19]:
-
-
-
sentence = 'three different words'
-words = sentence.split()
-print(words)
-
- -
-
-
- -
-
- - -
- -
- - -
-
['three', 'different', 'words']
-
-
-
- -
-
- -
-
-
-
In [20]:
-
-
-
type(words)
-
- -
-
-
- -
-
- - -
- -
Out[20]:
- - - - -
-
list
-
- -
- -
-
- -
-
-
-
In [21]:
-
-
-
secret_binary_data = '01001,101101,11100000'
-binaries = secret_binary_data.split(',')
-print(binaries)
-
- -
-
-
- -
-
- - -
- -
- - -
-
['01001', '101101', '11100000']
-
-
-
- -
-
- -
-
-
-
-
-

Calling multiple methods in a row

-
-
-
-
-
-
In [22]:
-
-
-
ugly_mixed_case = '   ThIS LooKs BAd '
-pretty = ugly_mixed_case.strip().lower().replace('bad', 'good')
-print(pretty)
-
- -
-
-
- -
-
- - -
- -
- - -
-
this looks good
-
-
-
- -
-
- -
-
-
-
-
-

Note that execution order is from left to right. Thus, this won't work:

- -
-
-
-
-
-
In [23]:
-
-
-
pretty = ugly_mixed_case.replace('bad', 'good').strip().lower()
-print(pretty)
-
- -
-
-
- -
-
- - -
- -
- - -
-
this looks bad
-
-
-
- -
-
- -
-
-
- -
-
-
-
In [24]:
-
-
-
two_lines = 'First line\nSecond line'
-print(two_lines)
-
- -
-
-
- -
-
- - -
- -
- - -
-
First line
-Second line
-
-
-
- -
-
- -
-
-
-
In [25]:
-
-
-
indented = '\tThis will be indented'
-print(indented)
-
- -
-
-
- -
-
- - -
- -
- - -
-
	This will be indented
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/testing1.html b/notebooks/beginner/html/testing1.html deleted file mode 100644 index 18e5eef..0000000 --- a/notebooks/beginner/html/testing1.html +++ /dev/null @@ -1,12007 +0,0 @@ - - - -tmp_testing1 - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Testing with pytest - part 1

-
-
-
-
-
-
-
-

Why to write tests?

    -
  • Who wants to perform manual testing?
  • -
  • When you fix a bug or add a new feature, tests are a way to verify that you did not break anything on the way
  • -
  • If you have clear requirements, you can have matching test(s) for each requirement
  • -
  • You don't have to be afraid of refactoring
  • -
  • Tests document your implementation - they show other people use cases of your implementation
  • -
  • This list is endless...
  • -
- -
-
-
-
-
-
-
-

Test-driven development aka TDD

In short, the basic idea of TDD is to write tests before writing the actual implementation. Maybe the most significant benefit of the approach is that the developer focuses on writing tests which match with what the program should do. Whereas if the tests are written after the actual implementation, there is a high risk for rushing tests which just show green light for the already written logic.

-

Tests are first class citizens in modern, agile software development, which is why it's important to start thinking TDD early during your Python learning path.

-

The workflow of TDD can be summarized as follows:

-
    -
  1. Add a test case(s) for the change / feature / bug fix you are going to implement
  2. -
  3. Run all tests and check that the new one fails
  4. -
  5. Implement required changes
  6. -
  7. Run tests and verify that all pass
  8. -
  9. Refactor
  10. -
- -
-
-
-
-
-
-
-

Running pytest inside notebooks

These are the steps required to run pytest inside Jupyter cells. You can copy the content of this cell to the top of your notebook which contains tests.

- -
-
-
-
-
-
In [1]:
-
-
-
# Let's make sure pytest and ipytest packages are installed
-# ipytest is required for running pytest inside Jupyter notebooks
-import sys
-!{sys.executable} -m pip install pytest
-!{sys.executable} -m pip install ipytest
-
-import ipytest.magics
-import pytest
-
-# Filename has to be set explicitly for ipytest 
-__file__ = 'testing1.ipynb'
-
- -
-
-
- -
-
- - -
- -
- - -
-
Requirement already satisfied: pytest in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (3.5.0)
-Requirement already satisfied: more-itertools>=4.0.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (4.1.0)
-Requirement already satisfied: setuptools in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (39.0.1)
-Requirement already satisfied: attrs>=17.4.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (17.4.0)
-Requirement already satisfied: six>=1.10.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (1.11.0)
-Requirement already satisfied: py>=1.5.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (1.5.3)
-Requirement already satisfied: pluggy<0.7,>=0.5 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (0.6.0)
-Requirement already satisfied: ipytest in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (0.2.2)
-
-
-
- -
-
- -
-
-
-
-
-

pytest test cases

Let's consider we have a function called sum_of_three_numbers for which we want to write a test.

- -
-
-
-
-
-
In [2]:
-
-
-
# This would be in your e.g. implementation.py
-def sum_of_three_numbers(num1, num2, num3):
-    return num1 + num2 + num3
-
- -
-
-
- -
-
-
-
-
-

Pytest test cases are actually quite similar as you have already seen in the exercises. Most of the exercises are structured like pytest test cases by dividing each exercise into three cells:

-
    -
  1. Setup the variables used in the test
  2. -
  3. Your implementation
  4. -
  5. Verify that your implementation does what is wanted by using assertions
  6. -
-

See the example test case below to see the similarities between the exercises and common structure of test cases.

- -
-
-
-
-
-
In [3]:
-
-
-
%%run_pytest[clean]
-# Mention this at the top of cells which contain test(s)
-# This is only required for running pytest in Jupyter notebooks
-
-
-# This would be in your test_implementation.py
-def test_sum_of_three_numbers():
-    # 1. Setup the variables used in the test
-    num1 = 2
-    num2 = 3
-    num3 = 5
-    
-    # 2. Call the functionality you want to test
-    result = sum_of_three_numbers(num1, num2, num3)
-    
-    # 3. Verify that the outcome is expected
-    assert result == 10
-
- -
-
-
- -
-
- - -
- -
- - -
-
=============================================================== test session starts ================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 1 item
-
-testing1.py .                                                                                                                                [100%]
-
-============================================================= 1 passed in 0.01 seconds =============================================================
-
-
-
- -
-
- -
-
-
-
-
-

Now go ahead and change the line assert result == 10 such that the assertion fails to see the output of a failed test.

- -
-
-
-
-
- - - - - - diff --git a/notebooks/beginner/html/testing2.html b/notebooks/beginner/html/testing2.html deleted file mode 100644 index 4e4ab01..0000000 --- a/notebooks/beginner/html/testing2.html +++ /dev/null @@ -1,12097 +0,0 @@ - - - -tmp_testing2 - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Testing with pytest - part 2

-
-
-
-
-
-
In [1]:
-
-
-
# Let's make sure pytest and ipytest packages are installed
-# ipytest is required for running pytest inside Jupyter notebooks
-import sys
-!{sys.executable} -m pip install pytest
-!{sys.executable} -m pip install ipytest
-
-import ipytest.magics
-import pytest
-__file__ = 'testing2.ipynb'
-
- -
-
-
- -
-
- - -
- -
- - -
-
Requirement already satisfied: pytest in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (3.5.0)
-Requirement already satisfied: setuptools in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (39.0.1)
-Requirement already satisfied: attrs>=17.4.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (17.4.0)
-Requirement already satisfied: more-itertools>=4.0.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (4.1.0)
-Requirement already satisfied: pluggy<0.7,>=0.5 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (0.6.0)
-Requirement already satisfied: py>=1.5.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (1.5.3)
-Requirement already satisfied: six>=1.10.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (1.11.0)
-Requirement already satisfied: ipytest in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (0.2.2)
-
-
-
- -
-
- -
-
-
-
-
-

@pytest.fixture

Let's consider we have an implemention of Person class which we want to test.

- -
-
-
-
-
-
In [2]:
-
-
-
# This would be e.g. in person.py
-class Person:
-    def __init__(self, first_name, last_name, age):
-        self.first_name = first_name
-        self.last_name = last_name
-        self.age = age
-    
-    @property
-    def full_name(self):
-        return '{} {}'.format(self.first_name, self.last_name)
-    
-    @property
-    def as_dict(self):
-        return {'name': self.full_name, 'age': self.age}
-        
-    def increase_age(self, years):
-        if years < 0:
-            raise ValueError('Can not make people younger :(')
-        self.age += years
-
- -
-
-
- -
-
-
-
-
-

You can easily create resusable testing code by using pytest fixtures. If you introduce your fixtures inside conftest.py, the fixtures are available for all your test cases. In general, the location of conftest.py is at the root of your tests directory.

- -
-
-
-
-
-
In [3]:
-
-
-
# This would be in either conftest.py or test_person.py
-@pytest.fixture()
-def default_person():
-    person = Person(first_name='John', last_name='Doe', age=82)
-    return person
-
- -
-
-
- -
-
-
-
-
-

Then you can utilize default_person fixture in the actual test cases.

- -
-
-
-
-
-
In [4]:
-
-
-
%%run_pytest[clean]
-
-# These would be in test_person.py
-def test_full_name(default_person): # Note: we use fixture as an argument of the test case
-    result = default_person.full_name
-    assert result == 'John Doe'
-    
-    
-def test_as_dict(default_person):
-    expected = {'name': 'John Doe', 'age': 82}
-    result = default_person.as_dict
-    assert result == expected
-    
-    
-def test_increase_age(default_person):
-    default_person.increase_age(1)
-    assert default_person.age == 83
-    
-    default_person.increase_age(10)
-    assert default_person.age == 93
-    
-    
-def test_increase_age_with_negative_number(default_person):
-    with pytest.raises(ValueError):
-        default_person.increase_age(-1)
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================================= test session starts =================================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 4 items
-
-testing2.py ....                                                                                                                                                                                                [100%]
-
-============================================================================================== 4 passed in 0.02 seconds ===============================================================================================
-
-
-
- -
-
- -
-
-
-
-
-

By using a fixture, we could use the same default_person for all our four test cases!

-

In the test_increase_age_with_negative_number we used pytest.raises to verify that an exception is raised.

- -
-
-
-
-
-
-
-

@pytest.mark.parametrize

Sometimes you want to test the same functionality with multiple different inputs. pytest.mark.parametrize is your solution for defining multiple different inputs with expected outputs. Let's consider the following implementation of replace_names function.

- -
-
-
-
-
-
In [5]:
-
-
-
# This would be e.g. in string_manipulate.py
-def replace_names(original_str, new_name):
-    """Replaces names (uppercase words) of original_str by new_name"""
-    words = original_str.split()
-    manipulated_words = [new_name if w.istitle() else w for w in words]
-    return ' '.join(manipulated_words)
-
- -
-
-
- -
-
-
-
-
-

We can test the replace_names function with multiple inputs by using pytest.mark.parametrize.

- -
-
-
-
-
-
In [6]:
-
-
-
%%run_pytest[clean]
-
-# This would be in your test module
-@pytest.mark.parametrize("original,new_name,expected", [
-        ('this is Lisa', 'John Doe', 'this is John Doe'),
-        ('how about Frank and Amy', 'John', 'how about John and John'),
-        ('no names here', 'John Doe', 'no names here'),
-    ])
-def test_replace_names(original, new_name, expected):
-    result = replace_names(original, new_name)
-    assert result == expected
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================================= test session starts =================================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 3 items
-
-testing2.py ...                                                                                                                                                                                                 [100%]
-
-================================================================================================== warnings summary ===================================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================================== 3 passed, 1 warnings in 0.03 seconds =========================================================================================
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/beginner/html/venv.html b/notebooks/beginner/html/venv.html deleted file mode 100644 index 4444ed7..0000000 --- a/notebooks/beginner/html/venv.html +++ /dev/null @@ -1,11874 +0,0 @@ - - - -tmp_venv - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Virtual environment

When working with Python projects, best practice is to have a separate virtual environment for each of them.

-

Each virtual environment has its own Python binary. When you install some Python package into your virtual environment, it'll be installed only into that specific environment. This means that you can have different versions of a single Python package in different virtual environments in the same machine. Virtual environments are also useful if you need to use different Python versions in your projects.

- -
-
-
-
-
-
-
-

venv

-
-
-
-
-
-
-
-

Creating new virtual environment

You can create all your virtual environments into a single directory (for example, .virtualenvs directory inside your home folder). This makes them easier to find.

- -
-
-
-
-
-
-
-

python3 -m venv /path/to/new/environment

-

or

-

path/to/your/python -m venv /path/to/new/environment

- -
-
-
-
-
-
-
-

Activating the virtual environment

-
-
-
-
-
-
-
-

Windows: path_to_virtual_env\Scripts\activate.bat
-Posix: source path_to_virtual_env/bin/activate

- -
-
-
-
-
-
-
-

Installing packages

After activating the newly created virtual environment, you can install new packages by using pip. For example if you want to install pytest:

-

python -m pip install pytest

-

it'll be installed into path_to_virtual_env/lib//site-packages. Note that the path to site-packages maybe slightly different depending on the operating system you are using.

-

You can list the installed packages and their versions by running:

-

python -m pip freeze

- -
-
-
-
-
- - - - - - diff --git a/notebooks/beginner/notebooks/strings.ipynb b/notebooks/beginner/notebooks/01_strings.ipynb similarity index 75% rename from notebooks/beginner/notebooks/strings.ipynb rename to notebooks/beginner/notebooks/01_strings.ipynb index c87bba4..fdbb05a 100644 --- a/notebooks/beginner/notebooks/strings.ipynb +++ b/notebooks/beginner/notebooks/01_strings.ipynb @@ -13,7 +13,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_string = 'Python is my favorite programming language!'" + "my_string = \"Python is my favorite programming language!\"" ] }, { @@ -56,10 +56,12 @@ "metadata": {}, "outputs": [], "source": [ - "long_story = ('Lorem ipsum dolor sit amet, consectetur adipiscing elit.' \n", - " 'Pellentesque eget tincidunt felis. Ut ac vestibulum est.' \n", - " 'In sed ipsum sit amet sapien scelerisque bibendum. Sed ' \n", - " 'sagittis purus eu diam fermentum pellentesque.')\n", + "long_story = (\n", + " \"Lorem ipsum dolor sit amet, consectetur adipiscing elit.\"\n", + " \"Pellentesque eget tincidunt felis. Ut ac vestibulum est.\"\n", + " \"In sed ipsum sit amet sapien scelerisque bibendum. Sed \"\n", + " \"sagittis purus eu diam fermentum pellentesque.\"\n", + ")\n", "long_story" ] }, @@ -99,7 +101,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_string.replace('a', '?')\n", + "my_string.replace(\"a\", \"?\")\n", "print(my_string)" ] }, @@ -116,7 +118,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_modified_string = my_string.replace('is', 'will be')\n", + "my_modified_string = my_string.replace(\"is\", \"will be\")\n", "print(my_modified_string)" ] }, @@ -133,7 +135,7 @@ "metadata": {}, "outputs": [], "source": [ - "secret = '{} is cool'.format('Python')\n", + "secret = \"{} is cool\".format(\"Python\")\n", "print(secret)" ] }, @@ -143,9 +145,13 @@ "metadata": {}, "outputs": [], "source": [ - "print('My name is {} {}, you can call me {}.'.format('John', 'Doe', 'John'))\n", + "print(\"My name is {} {}, you can call me {}.\".format(\"John\", \"Doe\", \"John\"))\n", "# is the same as:\n", - "print('My name is {first} {family}, you can call me {first}.'.format(first='John', family='Doe'))" + "print(\n", + " \"My name is {first} {family}, you can call me {first}.\".format(\n", + " first=\"John\", family=\"Doe\"\n", + " )\n", + ")" ] }, { @@ -161,10 +167,10 @@ "metadata": {}, "outputs": [], "source": [ - "pandas = 'pandas'\n", - "numpy = 'numpy'\n", - "requests = 'requests'\n", - "cool_python_libs = ', '.join([pandas, numpy, requests])" + "pandas = \"pandas\"\n", + "numpy = \"numpy\"\n", + "requests = \"requests\"\n", + "cool_python_libs = \", \".join([pandas, numpy, requests])" ] }, { @@ -173,7 +179,7 @@ "metadata": {}, "outputs": [], "source": [ - "print('Some cool python libraries: {}'.format(cool_python_libs))" + "print(\"Some cool python libraries: {}\".format(cool_python_libs))" ] }, { @@ -189,13 +195,13 @@ "metadata": {}, "outputs": [], "source": [ - "cool_python_libs = pandas + ', ' + numpy + ', ' + requests\n", - "print('Some cool python libraries: {}'.format(cool_python_libs))\n", + "cool_python_libs = pandas + \", \" + numpy + \", \" + requests\n", + "print(\"Some cool python libraries: {}\".format(cool_python_libs))\n", "\n", "cool_python_libs = pandas\n", - "cool_python_libs += ', ' + numpy\n", - "cool_python_libs += ', ' + requests\n", - "print('Some cool python libraries: {}'.format(cool_python_libs))" + "cool_python_libs += \", \" + numpy\n", + "cool_python_libs += \", \" + requests\n", + "print(\"Some cool python libraries: {}\".format(cool_python_libs))" ] }, { @@ -211,7 +217,7 @@ "metadata": {}, "outputs": [], "source": [ - "mixed_case = 'PyTHoN hackER'" + "mixed_case = \"PyTHoN hackER\"" ] }, { @@ -254,11 +260,11 @@ "metadata": {}, "outputs": [], "source": [ - "ugly_formatted = ' \\n \\t Some story to tell '\n", + "ugly_formatted = \" \\n \\t Some story to tell \"\n", "stripped = ugly_formatted.strip()\n", "\n", - "print('ugly: {}'.format(ugly_formatted))\n", - "print('stripped: {}'.format(ugly_formatted.strip()))" + "print(\"ugly: {}\".format(ugly_formatted))\n", + "print(\"stripped: {}\".format(ugly_formatted.strip()))" ] }, { @@ -274,7 +280,7 @@ "metadata": {}, "outputs": [], "source": [ - "sentence = 'three different words'\n", + "sentence = \"three different words\"\n", "words = sentence.split()\n", "print(words)" ] @@ -294,8 +300,8 @@ "metadata": {}, "outputs": [], "source": [ - "secret_binary_data = '01001,101101,11100000'\n", - "binaries = secret_binary_data.split(',')\n", + "secret_binary_data = \"01001,101101,11100000\"\n", + "binaries = secret_binary_data.split(\",\")\n", "print(binaries)" ] }, @@ -312,8 +318,8 @@ "metadata": {}, "outputs": [], "source": [ - "ugly_mixed_case = ' ThIS LooKs BAd '\n", - "pretty = ugly_mixed_case.strip().lower().replace('bad', 'good')\n", + "ugly_mixed_case = \" ThIS LooKs BAd \"\n", + "pretty = ugly_mixed_case.strip().lower().replace(\"bad\", \"good\")\n", "print(pretty)" ] }, @@ -330,7 +336,7 @@ "metadata": {}, "outputs": [], "source": [ - "pretty = ugly_mixed_case.replace('bad', 'good').strip().lower()\n", + "pretty = ugly_mixed_case.replace(\"bad\", \"good\").strip().lower()\n", "print(pretty)" ] }, @@ -347,7 +353,7 @@ "metadata": {}, "outputs": [], "source": [ - "two_lines = 'First line\\nSecond line'\n", + "two_lines = \"First line\\nSecond line\"\n", "print(two_lines)" ] }, @@ -357,7 +363,7 @@ "metadata": {}, "outputs": [], "source": [ - "indented = '\\tThis will be indented'\n", + "indented = \"\\tThis will be indented\"\n", "print(indented)" ] } diff --git a/notebooks/beginner/notebooks/numbers.ipynb b/notebooks/beginner/notebooks/02_numbers.ipynb similarity index 82% rename from notebooks/beginner/notebooks/numbers.ipynb rename to notebooks/beginner/notebooks/02_numbers.ipynb index 95f45c5..45af1a7 100644 --- a/notebooks/beginner/notebooks/numbers.ipynb +++ b/notebooks/beginner/notebooks/02_numbers.ipynb @@ -17,13 +17,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ "my_int = 6\n", - "print('value: {}, type: {}'.format(my_int, type(my_int)))" + "print(\"value: {}, type: {}\".format(my_int, type(my_int)))" ] }, { @@ -36,13 +34,11 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ "my_float = float(my_int)\n", - "print('value: {}, type: {}'.format(my_float, type(my_float)))" + "print(\"value: {}, type: {}\".format(my_float, type(my_float)))" ] }, { @@ -72,9 +68,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ "val = 0.1 + 0.1 + 0.1\n", @@ -113,7 +107,7 @@ "metadata": {}, "outputs": [], "source": [ - "2 ** 3" + "2**3" ] }, { @@ -127,9 +121,7 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ "from decimal import Decimal" @@ -138,27 +130,23 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ "from_float = Decimal(0.1)\n", - "from_str = Decimal('0.1')\n", - "print('from float: {}\\nfrom string: {}'.format(from_float, from_str))" + "from_str = Decimal(\"0.1\")\n", + "print(\"from float: {}\\nfrom string: {}\".format(from_float, from_str))" ] }, { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ - "my_decimal = Decimal('0.1')\n", + "my_decimal = Decimal(\"0.1\")\n", "sum_of_decimals = my_decimal + my_decimal + my_decimal\n", - "print(sum_of_decimals == Decimal('0.3'))" + "print(sum_of_decimals == Decimal(\"0.3\"))" ] }, { @@ -175,7 +163,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(1 + 2**2 * 3 / 6) # 1 + 4 * 3 / 6 == 1 + 12 / 6 == 1 + 2\n", + "print(1 + 2**2 * 3 / 6) # 1 + 4 * 3 / 6 == 1 + 12 / 6 == 1 + 2\n", "print((1 + 2**2) * 3 / 6)" ] } diff --git a/notebooks/beginner/notebooks/conditionals.ipynb b/notebooks/beginner/notebooks/03_conditionals.ipynb similarity index 58% rename from notebooks/beginner/notebooks/conditionals.ipynb rename to notebooks/beginner/notebooks/03_conditionals.ipynb index 3850f20..9600954 100644 --- a/notebooks/beginner/notebooks/conditionals.ipynb +++ b/notebooks/beginner/notebooks/03_conditionals.ipynb @@ -1,5 +1,30 @@ { "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from IPython.display import HTML\n", + "\n", + "HTML(\n", + " \"\"\"\n", + "
\"\"\"\n", + ")" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -27,7 +52,7 @@ "metadata": {}, "outputs": [], "source": [ - "print('type of True and False: {}'.format(type(True)))" + "print(\"type of True and False: {}\".format(type(True)))" ] }, { @@ -36,9 +61,9 @@ "metadata": {}, "outputs": [], "source": [ - "print('0: {}, 1: {}'.format(bool(0), bool(1)))\n", - "print('empty list: {}, list with values: {}'.format(bool([]), bool(['woop'])))\n", - "print('empty dict: {}, dict with values: {}'.format(bool({}), bool({'Python': 'cool'})))" + "print(\"0: {}, 1: {}\".format(bool(0), bool(1)))\n", + "print(\"empty list: {}, list with values: {}\".format(bool([]), bool([\"woop\"])))\n", + "print(\"empty dict: {}, dict with values: {}\".format(bool({}), bool({\"Python\": \"cool\"})))" ] }, { @@ -54,16 +79,16 @@ "metadata": {}, "outputs": [], "source": [ - "print('1 == 0: {}'.format(1 == 0))\n", - "print('1 != 0: {}'.format(1 != 0))\n", - "print('1 > 0: {}'.format(1 > 0))\n", - "print('1 > 1: {}'.format(1 > 1))\n", - "print('1 < 0: {}'.format(1 < 0))\n", - "print('1 < 1: {}'.format(1 < 1))\n", - "print('1 >= 0: {}'.format(1 >= 0))\n", - "print('1 >= 1: {}'.format(1 >= 1))\n", - "print('1 <= 0: {}'.format(1 <= 0))\n", - "print('1 <= 1: {}'.format(1 <= 1))" + "print(\"1 == 0: {}\".format(1 == 0))\n", + "print(\"1 != 0: {}\".format(1 != 0))\n", + "print(\"1 > 0: {}\".format(1 > 0))\n", + "print(\"1 > 1: {}\".format(1 > 1))\n", + "print(\"1 < 0: {}\".format(1 < 0))\n", + "print(\"1 < 1: {}\".format(1 < 1))\n", + "print(\"1 >= 0: {}\".format(1 >= 0))\n", + "print(\"1 >= 1: {}\".format(1 >= 1))\n", + "print(\"1 <= 0: {}\".format(1 <= 0))\n", + "print(\"1 <= 1: {}\".format(1 <= 1))" ] }, { @@ -79,7 +104,7 @@ "metadata": {}, "outputs": [], "source": [ - "print('1 <= 2 <= 3: {}'.format(1 <= 2 <= 3))" + "print(\"1 <= 2 <= 3: {}\".format(1 <= 2 <= 3))" ] }, { @@ -107,8 +132,8 @@ "metadata": {}, "outputs": [], "source": [ - "print('Python and java are both cool: {}'.format(python_is_cool and java_is_cool))\n", - "print('secret_value and python_is_cool: {}'.format(secret_value and python_is_cool))" + "print(\"Python and java are both cool: {}\".format(python_is_cool and java_is_cool))\n", + "print(\"secret_value and python_is_cool: {}\".format(secret_value and python_is_cool))" ] }, { @@ -117,8 +142,8 @@ "metadata": {}, "outputs": [], "source": [ - "print('Python or java is cool: {}'.format(python_is_cool or java_is_cool))\n", - "print('1 >= 1.1 or 2 < float(\"1.4\"): {}'.format(1 >= 1.1 or 2 < float('1.4')))" + "print(\"Python or java is cool: {}\".format(python_is_cool or java_is_cool))\n", + "print('1 >= 1.1 or 2 < float(\"1.4\"): {}'.format(1 >= 1.1 or 2 < float(\"1.4\")))" ] }, { @@ -127,7 +152,7 @@ "metadata": {}, "outputs": [], "source": [ - "print('Java is not cool: {}'.format(not java_is_cool))" + "print(\"Java is not cool: {}\".format(not java_is_cool))" ] }, { @@ -143,8 +168,8 @@ "metadata": {}, "outputs": [], "source": [ - "print(bool(not java_is_cool or secret_value and python_is_cool or empty_list))\n", - "print(bool(not (java_is_cool or secret_value and python_is_cool or empty_list)))" + "print(bool(not java_is_cool or secret_value and python_is_cool or empty_list))\n", + "print(bool(not (java_is_cool or secret_value and python_is_cool or empty_list)))" ] }, { @@ -162,10 +187,10 @@ "source": [ "statement = True\n", "if statement:\n", - " print('statement is True')\n", - " \n", + " print(\"statement is True\")\n", + "\n", "if not statement:\n", - " print('statement is not True')" + " print(\"statement is not True\")" ] }, { @@ -177,7 +202,7 @@ "empty_list = []\n", "# With if and elif, conversion to `bool` is implicit\n", "if empty_list:\n", - " print('empty list will not evaluate to True') # this won't be executed" + " print(\"empty list will not evaluate to True\") # this won't be executed" ] }, { @@ -188,7 +213,7 @@ "source": [ "val = 3\n", "if 0 <= val < 1 or val == 3:\n", - " print('Value is positive and less than one or value is three')" + " print(\"Value is positive and less than one or value is three\")" ] }, { @@ -206,9 +231,9 @@ "source": [ "my_dict = {}\n", "if my_dict:\n", - " print('there is something in my dict')\n", + " print(\"there is something in my dict\")\n", "else:\n", - " print('my dict is empty :(')" + " print(\"my dict is empty :(\")" ] }, { @@ -226,11 +251,11 @@ "source": [ "val = 88\n", "if val >= 100:\n", - " print('value is equal or greater than 100')\n", + " print(\"value is equal or greater than 100\")\n", "elif val > 10:\n", - " print('value is greater than 10 but less than 100')\n", + " print(\"value is greater than 10 but less than 100\")\n", "else:\n", - " print('value is equal or less than 10')" + " print(\"value is equal or less than 10\")" ] }, { @@ -246,18 +271,18 @@ "metadata": {}, "outputs": [], "source": [ - "greeting = 'Hello fellow Pythonista!'\n", - "language = 'Italian'\n", + "greeting = \"Hello fellow Pythonista!\"\n", + "language = \"Italian\"\n", + "\n", + "if language == \"Swedish\":\n", + " greeting = \"Hejsan!\"\n", + "elif language == \"Finnish\":\n", + " greeting = \"Latua perkele!\"\n", + "elif language == \"Spanish\":\n", + " greeting = \"Hola!\"\n", + "elif language == \"German\":\n", + " greeting = \"Guten Tag!\"\n", "\n", - "if language == 'Swedish':\n", - " greeting = 'Hejsan!'\n", - "elif language == 'Finnish':\n", - " greeting = 'Latua perkele!'\n", - "elif language == 'Spanish':\n", - " greeting = 'Hola!'\n", - "elif language == 'German':\n", - " greeting = 'Guten Tag!'\n", - " \n", "print(greeting)" ] }, @@ -271,7 +296,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -285,7 +310,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.10.3" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/lists.ipynb b/notebooks/beginner/notebooks/04_lists.ipynb similarity index 75% rename from notebooks/beginner/notebooks/lists.ipynb rename to notebooks/beginner/notebooks/04_lists.ipynb index 0a08876..2820efd 100644 --- a/notebooks/beginner/notebooks/lists.ipynb +++ b/notebooks/beginner/notebooks/04_lists.ipynb @@ -14,7 +14,7 @@ "outputs": [], "source": [ "my_empty_list = []\n", - "print('empty list: {}, type: {}'.format(my_empty_list, type(my_empty_list)))" + "print(\"empty list: {}, type: {}\".format(my_empty_list, type(my_empty_list)))" ] }, { @@ -24,8 +24,8 @@ "outputs": [], "source": [ "list_of_ints = [1, 2, 6, 7]\n", - "list_of_misc = [0.2, 5, 'Python', 'is', 'still fun', '!']\n", - "print('lengths: {} and {}'.format(len(list_of_ints), len(list_of_misc)))" + "list_of_misc = [0.2, 5, \"Python\", \"is\", \"still fun\", \"!\"]\n", + "print(\"lengths: {} and {}\".format(len(list_of_ints), len(list_of_misc)))" ] }, { @@ -41,7 +41,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_list = ['Python', 'is', 'still', 'cool']\n", + "my_list = [\"Python\", \"is\", \"still\", \"cool\"]\n", "print(my_list[0])\n", "print(my_list[3])" ] @@ -53,8 +53,8 @@ "outputs": [], "source": [ "coordinates = [[12.0, 13.3], [0.6, 18.0], [88.0, 1.1]] # two dimensional\n", - "print('first coordinate: {}'.format(coordinates[0]))\n", - "print('second element of first coordinate: {}'.format(coordinates[0][1]))" + "print(\"first coordinate: {}\".format(coordinates[0]))\n", + "print(\"second element of first coordinate: {}\".format(coordinates[0][1]))" ] }, { @@ -92,9 +92,9 @@ "metadata": {}, "outputs": [], "source": [ - "languages = ['Java', 'C++', 'Go', 'Python', 'JavaScript']\n", - "if 'Python' in languages:\n", - " print('Python is there!')" + "languages = [\"Java\", \"C++\", \"Go\", \"Python\", \"JavaScript\"]\n", + "if \"Python\" in languages:\n", + " print(\"Python is there!\")" ] }, { @@ -104,7 +104,7 @@ "outputs": [], "source": [ "if 6 not in [1, 2, 3, 7]:\n", - " print('number 6 is not present')" + " print(\"number 6 is not present\")" ] }, { @@ -123,7 +123,7 @@ "original = [1, 2, 3]\n", "modified = original\n", "modified[0] = 99\n", - "print('original: {}, modified: {}'.format(original, modified))" + "print(\"original: {}, modified: {}\".format(original, modified))" ] }, { @@ -140,11 +140,11 @@ "outputs": [], "source": [ "original = [1, 2, 3]\n", - "modified = list(original) # Note list() \n", + "modified = list(original) # Note list()\n", "# Alternatively, you can use copy method\n", "# modified = original.copy()\n", "modified[0] = 99\n", - "print('original: {}, modified: {}'.format(original, modified))" + "print(\"original: {}, modified: {}\".format(original, modified))" ] }, { @@ -161,7 +161,7 @@ "outputs": [], "source": [ "my_list = [1]\n", - "my_list.append('ham')\n", + "my_list.append(\"ham\")\n", "print(my_list)" ] }, @@ -178,15 +178,15 @@ "metadata": {}, "outputs": [], "source": [ - "my_list = ['Python', 'is', 'sometimes', 'fun']\n", - "my_list.remove('sometimes')\n", + "my_list = [\"Python\", \"is\", \"sometimes\", \"fun\"]\n", + "my_list.remove(\"sometimes\")\n", "print(my_list)\n", "\n", "# If you are not sure that the value is in list, better to check first:\n", - "if 'Java' in my_list:\n", - " my_list.remove('Java')\n", + "if \"Java\" in my_list:\n", + " my_list.remove(\"Java\")\n", "else:\n", - " print('Java is not part of this story.')" + " print(\"Java is not part of this story.\")" ] }, { @@ -204,14 +204,14 @@ "source": [ "numbers = [8, 1, 6, 5, 10]\n", "numbers.sort()\n", - "print('numbers: {}'.format(numbers))\n", + "print(\"numbers: {}\".format(numbers))\n", "\n", "numbers.sort(reverse=True)\n", - "print('numbers reversed: {}'.format(numbers))\n", + "print(\"numbers reversed: {}\".format(numbers))\n", "\n", - "words = ['this', 'is', 'a', 'list', 'of', 'words']\n", + "words = [\"this\", \"is\", \"a\", \"list\", \"of\", \"words\"]\n", "words.sort()\n", - "print('words: {}'.format(words))" + "print(\"words: {}\".format(words))" ] }, { @@ -230,7 +230,7 @@ "source": [ "numbers = [8, 1, 6, 5, 10]\n", "sorted_numbers = sorted(numbers)\n", - "print('numbers: {}, sorted: {}'.format(numbers, sorted_numbers))" + "print(\"numbers: {}, sorted: {}\".format(numbers, sorted_numbers))" ] }, { @@ -246,10 +246,10 @@ "metadata": {}, "outputs": [], "source": [ - "first_list = ['beef', 'ham']\n", - "second_list = ['potatoes',1 ,3]\n", + "first_list = [\"beef\", \"ham\"]\n", + "second_list = [\"potatoes\", 1, 3]\n", "first_list.extend(second_list)\n", - "print('first: {}, second: {}'.format(first_list, second_list))" + "print(\"first: {}, second: {}\".format(first_list, second_list))" ] }, { @@ -268,11 +268,11 @@ "first = [1, 2, 3]\n", "second = [4, 5]\n", "first += second # same as: first = first + second\n", - "print('first: {}'.format(first))\n", + "print(\"first: {}\".format(first))\n", "\n", "# If you need a new list\n", "summed = first + second\n", - "print('summed: {}'.format(summed))" + "print(\"summed: {}\".format(summed))" ] }, { @@ -288,7 +288,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_list = ['a', 'b', 'ham']\n", + "my_list = [\"a\", \"b\", \"ham\"]\n", "my_list.reverse()\n", "print(my_list)" ] diff --git a/notebooks/beginner/notebooks/dictionaries.ipynb b/notebooks/beginner/notebooks/05_dictionaries.ipynb similarity index 66% rename from notebooks/beginner/notebooks/dictionaries.ipynb rename to notebooks/beginner/notebooks/05_dictionaries.ipynb index f1b4f39..97aa70c 100644 --- a/notebooks/beginner/notebooks/dictionaries.ipynb +++ b/notebooks/beginner/notebooks/05_dictionaries.ipynb @@ -15,7 +15,7 @@ "outputs": [], "source": [ "my_empty_dict = {} # alternative: my_empty_dict = dict()\n", - "print('dict: {}, type: {}'.format(my_empty_dict, type(my_empty_dict)))" + "print(\"dict: {}, type: {}\".format(my_empty_dict, type(my_empty_dict)))" ] }, { @@ -31,14 +31,14 @@ "metadata": {}, "outputs": [], "source": [ - "dict1 = {'value1': 1.6, 'value2': 10, 'name': 'John Doe'}\n", - "dict2 = dict(value1=1.6, value2=10, name='John Doe')\n", + "dict1 = {\"value1\": 1.6, \"value2\": 10, \"name\": \"John Doe\"}\n", + "dict2 = dict(value1=1.6, value2=10, name=\"John Doe\")\n", "\n", "print(dict1)\n", "print(dict2)\n", "\n", - "print('equal: {}'.format(dict1 == dict2))\n", - "print('length: {}'.format(len(dict1)))" + "print(\"equal: {}\".format(dict1 == dict2))\n", + "print(\"length: {}\".format(len(dict1)))" ] }, { @@ -54,9 +54,9 @@ "metadata": {}, "outputs": [], "source": [ - "print('keys: {}'.format(dict1.keys()))\n", - "print('values: {}'.format(dict1.values()))\n", - "print('items: {}'.format(dict1.items()))" + "print(\"keys: {}\".format(dict1.keys()))\n", + "print(\"values: {}\".format(dict1.values()))\n", + "print(\"items: {}\".format(dict1.items()))" ] }, { @@ -73,11 +73,11 @@ "outputs": [], "source": [ "my_dict = {}\n", - "my_dict['key1'] = 'value1'\n", - "my_dict['key2'] = 99\n", - "my_dict['key1'] = 'new value' # overriding existing value\n", + "my_dict[\"key1\"] = \"value1\"\n", + "my_dict[\"key2\"] = 99\n", + "my_dict[\"key1\"] = \"new value\" # overriding existing value\n", "print(my_dict)\n", - "print('value of key1: {}'.format(my_dict['key1']))" + "print(\"value of key1: {}\".format(my_dict[\"key1\"]))" ] }, { @@ -109,16 +109,16 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'key1': 'value1', 'key2': 99, 'keyX': 'valueX'}\n", - "del my_dict['keyX']\n", + "my_dict = {\"key1\": \"value1\", \"key2\": 99, \"keyX\": \"valueX\"}\n", + "del my_dict[\"keyX\"]\n", "print(my_dict)\n", "\n", "# Usually better to make sure that the key exists (see also pop() and popitem())\n", - "key_to_delete = 'my_key'\n", + "key_to_delete = \"my_key\"\n", "if key_to_delete in my_dict:\n", " del my_dict[key_to_delete]\n", "else:\n", - " print('{key} is not in {dictionary}'.format(key=key_to_delete, dictionary=my_dict))" + " print(\"{key} is not in {dictionary}\".format(key=key_to_delete, dictionary=my_dict))" ] }, { @@ -134,12 +134,12 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'ham': 'good', 'carrot': 'semi good'}\n", + "my_dict = {\"ham\": \"good\", \"carrot\": \"semi good\"}\n", "my_other_dict = my_dict\n", - "my_other_dict['carrot'] = 'super tasty'\n", - "my_other_dict['sausage'] = 'best ever'\n", - "print('my_dict: {}\\nother: {}'.format(my_dict, my_other_dict))\n", - "print('equal: {}'.format(my_dict == my_other_dict))" + "my_other_dict[\"carrot\"] = \"super tasty\"\n", + "my_other_dict[\"sausage\"] = \"best ever\"\n", + "print(\"my_dict: {}\\nother: {}\".format(my_dict, my_other_dict))\n", + "print(\"equal: {}\".format(my_dict == my_other_dict))" ] }, { @@ -155,11 +155,11 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'ham': 'good', 'carrot': 'semi good'}\n", + "my_dict = {\"ham\": \"good\", \"carrot\": \"semi good\"}\n", "my_other_dict = dict(my_dict)\n", - "my_other_dict['beer'] = 'decent'\n", - "print('my_dict: {}\\nother: {}'.format(my_dict, my_other_dict))\n", - "print('equal: {}'.format(my_dict == my_other_dict))" + "my_other_dict[\"beer\"] = \"decent\"\n", + "print(\"my_dict: {}\\nother: {}\".format(my_dict, my_other_dict))\n", + "print(\"equal: {}\".format(my_dict == my_other_dict))" ] }, { @@ -177,12 +177,12 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'a': 1, 'b': 2, 'c': 3}\n", - "d = my_dict.get('d')\n", - "print('d: {}'.format(d))\n", + "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}\n", + "d = my_dict.get(\"d\")\n", + "print(\"d: {}\".format(d))\n", "\n", - "d = my_dict.get('d', 'my default value')\n", - "print('d: {}'.format(d))" + "d = my_dict.get(\"d\", \"my default value\")\n", + "print(\"d: {}\".format(d))" ] }, { @@ -198,16 +198,16 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = dict(food='ham', drink='beer', sport='football')\n", - "print('dict before pops: {}'.format(my_dict))\n", + "my_dict = dict(food=\"ham\", drink=\"beer\", sport=\"football\")\n", + "print(\"dict before pops: {}\".format(my_dict))\n", "\n", - "food = my_dict.pop('food')\n", - "print('food: {}'.format(food))\n", - "print('dict after popping food: {}'.format(my_dict))\n", + "food = my_dict.pop(\"food\")\n", + "print(\"food: {}\".format(food))\n", + "print(\"dict after popping food: {}\".format(my_dict))\n", "\n", - "food_again = my_dict.pop('food', 'default value for food')\n", - "print('food again: {}'.format(food_again))\n", - "print('dict after popping food again: {}'.format(my_dict))\n" + "food_again = my_dict.pop(\"food\", \"default value for food\")\n", + "print(\"food again: {}\".format(food_again))\n", + "print(\"dict after popping food again: {}\".format(my_dict))" ] }, { @@ -224,10 +224,10 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'a': 1, 'b': 2, 'c': 3}\n", - "a = my_dict.setdefault('a', 'my default value')\n", - "d = my_dict.setdefault('d', 'my default value')\n", - "print('a: {}\\nd: {}\\nmy_dict: {}'.format(a, d, my_dict))" + "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}\n", + "a = my_dict.setdefault(\"a\", \"my default value\")\n", + "d = my_dict.setdefault(\"d\", \"my default value\")\n", + "print(\"a: {}\\nd: {}\\nmy_dict: {}\".format(a, d, my_dict))" ] }, { @@ -244,13 +244,13 @@ "metadata": {}, "outputs": [], "source": [ - "dict1 = {'a': 1, 'b': 2}\n", - "dict2 = {'c': 3}\n", + "dict1 = {\"a\": 1, \"b\": 2}\n", + "dict2 = {\"c\": 3}\n", "dict1.update(dict2)\n", "print(dict1)\n", "\n", "# If they have same keys:\n", - "dict1.update({'c': 4})\n", + "dict1.update({\"c\": 4})\n", "print(dict1)" ] }, @@ -291,7 +291,7 @@ "metadata": {}, "outputs": [], "source": [ - "good_dict = {'my key': ['Python', 'is', 'still', 'cool']}\n", + "good_dict = {\"my key\": [\"Python\", \"is\", \"still\", \"cool\"]}\n", "print(good_dict)" ] } diff --git a/notebooks/beginner/notebooks/for_loops.ipynb b/notebooks/beginner/notebooks/06_for_loops.ipynb similarity index 91% rename from notebooks/beginner/notebooks/for_loops.ipynb rename to notebooks/beginner/notebooks/06_for_loops.ipynb index a61c1c1..eded387 100644 --- a/notebooks/beginner/notebooks/for_loops.ipynb +++ b/notebooks/beginner/notebooks/06_for_loops.ipynb @@ -20,7 +20,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_list = [1, 2, 3, 4, 'Python', 'is', 'neat']\n", + "my_list = [1, 2, 3, 4, \"Python\", \"is\", \"neat\"]\n", "for item in my_list:\n", " print(item)" ] @@ -40,7 +40,7 @@ "outputs": [], "source": [ "for item in my_list:\n", - " if item == 'Python':\n", + " if item == \"Python\":\n", " break\n", " print(item)" ] @@ -80,7 +80,7 @@ "outputs": [], "source": [ "for idx, val in enumerate(my_list):\n", - " print('idx: {}, value: {}'.format(idx, val))" + " print(\"idx: {}, value: {}\".format(idx, val))" ] }, { @@ -96,7 +96,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'hacker': True, 'age': 72, 'name': 'John Doe'}\n", + "my_dict = {\"hacker\": True, \"age\": 72, \"name\": \"John Doe\"}\n", "for val in my_dict:\n", " print(val)" ] @@ -108,7 +108,7 @@ "outputs": [], "source": [ "for key, val in my_dict.items():\n", - " print('{}={}'.format(key, val))" + " print(\"{}={}\".format(key, val))" ] }, { diff --git a/notebooks/beginner/notebooks/functions.ipynb b/notebooks/beginner/notebooks/07_functions.ipynb similarity index 86% rename from notebooks/beginner/notebooks/functions.ipynb rename to notebooks/beginner/notebooks/07_functions.ipynb index ca00f31..bd4957c 100644 --- a/notebooks/beginner/notebooks/functions.ipynb +++ b/notebooks/beginner/notebooks/07_functions.ipynb @@ -14,9 +14,10 @@ "outputs": [], "source": [ "def my_first_function():\n", - " print('Hello world!')\n", + " print(\"Hello world!\")\n", "\n", - "print('type: {}'.format(my_first_function))\n", + "\n", + "print(\"type: {}\".format(my_first_function))\n", "\n", "my_first_function() # Calling a function" ] @@ -35,9 +36,10 @@ "outputs": [], "source": [ "def greet_us(name1, name2):\n", - " print('Hello {} and {}!'.format(name1, name2))\n", + " print(\"Hello {} and {}!\".format(name1, name2))\n", + "\n", "\n", - "greet_us('John Doe', 'Superman')" + "greet_us(\"John Doe\", \"Superman\")" ] }, { @@ -51,9 +53,10 @@ " modified = original.strip().lower()\n", " return modified\n", "\n", - "uggly_string = ' MixED CaSe '\n", + "\n", + "uggly_string = \" MixED CaSe \"\n", "pretty = strip_and_lowercase(uggly_string)\n", - "print('pretty: {}'.format(pretty))" + "print(\"pretty: {}\".format(pretty))" ] }, { @@ -70,7 +73,8 @@ "outputs": [], "source": [ "def my_fancy_calculation(first, second, third):\n", - " return first + second - third \n", + " return first + second - third\n", + "\n", "\n", "print(my_fancy_calculation(3, 2, 1))\n", "\n", @@ -80,7 +84,7 @@ "print(my_fancy_calculation(third=1, first=3, second=2))\n", "\n", "# You can mix arguments and keyword arguments but you have to start with arguments\n", - "print(my_fancy_calculation(3, third=1, second=2)) " + "print(my_fancy_calculation(3, third=1, second=2))" ] }, { @@ -93,22 +97,21 @@ { "cell_type": "code", "execution_count": null, - "metadata": { - "scrolled": true - }, + "metadata": {}, "outputs": [], "source": [ "def create_person_info(name, age, job=None, salary=300):\n", - " info = {'name': name, 'age': age, 'salary': salary}\n", - " \n", + " info = {\"name\": name, \"age\": age, \"salary\": salary}\n", + "\n", " # Add 'job' key only if it's provided as parameter\n", - " if job: \n", + " if job:\n", " info.update(dict(job=job))\n", - " \n", + "\n", " return info\n", "\n", - "person1 = create_person_info('John Doe', 82) # use default values for job and salary\n", - "person2 = create_person_info('Lisa Doe', 22, 'hacker', 10000)\n", + "\n", + "person1 = create_person_info(\"John Doe\", 82) # use default values for job and salary\n", + "person2 = create_person_info(\"Lisa Doe\", 22, \"hacker\", 10000)\n", "print(person1)\n", "print(person2)" ] @@ -131,6 +134,7 @@ " magical_list.append(number)\n", " return magical_list\n", "\n", + "\n", "print(append_if_multiple_of_five(100))\n", "print(append_if_multiple_of_five(105))\n", "print(append_if_multiple_of_five(123))\n", @@ -158,6 +162,7 @@ " magical_list.append(number)\n", " return magical_list\n", "\n", + "\n", "print(append_if_multiple_of_five(100))\n", "print(append_if_multiple_of_five(105))\n", "print(append_if_multiple_of_five(123))\n", @@ -181,7 +186,8 @@ "source": [ "def print_sum(val1, val2):\n", " \"\"\"Function which prints the sum of given arguments.\"\"\"\n", - " print('sum: {}'.format(val1 + val2))\n", + " print(\"sum: {}\".format(val1 + val2))\n", + "\n", "\n", "print(help(print_sum))" ] @@ -193,7 +199,7 @@ "outputs": [], "source": [ "def calculate_sum(val1, val2):\n", - " \"\"\"This is a longer docstring defining also the args and the return value. \n", + " \"\"\"This is a longer docstring defining also the args and the return value.\n", "\n", " Args:\n", " val1: The first parameter.\n", @@ -201,10 +207,11 @@ "\n", " Returns:\n", " The sum of val1 and val2.\n", - " \n", + "\n", " \"\"\"\n", " return val1 + val2\n", "\n", + "\n", "print(help(calculate_sum))" ] }, @@ -225,6 +232,7 @@ "def my_function(some_argument):\n", " pass\n", "\n", + "\n", "def my_other_function():\n", " pass" ] diff --git a/notebooks/beginner/notebooks/testing1.ipynb b/notebooks/beginner/notebooks/08_testing1.ipynb similarity index 95% rename from notebooks/beginner/notebooks/testing1.ipynb rename to notebooks/beginner/notebooks/08_testing1.ipynb index 50a0bbb..562ab40 100644 --- a/notebooks/beginner/notebooks/testing1.ipynb +++ b/notebooks/beginner/notebooks/08_testing1.ipynb @@ -54,14 +54,14 @@ "# Let's make sure pytest and ipytest packages are installed\n", "# ipytest is required for running pytest inside Jupyter notebooks\n", "import sys\n", + "\n", "!{sys.executable} -m pip install pytest\n", "!{sys.executable} -m pip install ipytest\n", "\n", - "import ipytest.magics\n", - "import pytest\n", + "# These are needed for running pytest inside Jupyter notebooks\n", + "import ipytest\n", "\n", - "# Filename has to be set explicitly for ipytest \n", - "__file__ = 'testing1.ipynb'" + "ipytest.autoconfig()" ] }, { @@ -101,7 +101,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean]\n", + "%%ipytest\n", "# Mention this at the top of cells which contain test(s)\n", "# This is only required for running pytest in Jupyter notebooks\n", "\n", @@ -130,7 +130,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -144,7 +144,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.10.3" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/file_io.ipynb b/notebooks/beginner/notebooks/10_file_io.ipynb similarity index 76% rename from notebooks/beginner/notebooks/file_io.ipynb rename to notebooks/beginner/notebooks/10_file_io.ipynb index 76c8ee2..e9b4865 100644 --- a/notebooks/beginner/notebooks/file_io.ipynb +++ b/notebooks/beginner/notebooks/10_file_io.ipynb @@ -23,16 +23,16 @@ "source": [ "import os\n", "\n", - "current_file = os.path.realpath('file_io.ipynb') \n", - "print('current file: {}'.format(current_file))\n", + "current_file = os.path.realpath(\"file_io.ipynb\")\n", + "print(\"current file: {}\".format(current_file))\n", "# Note: in .py files you can get the path of current file by __file__\n", "\n", - "current_dir = os.path.dirname(current_file) \n", - "print('current directory: {}'.format(current_dir))\n", + "current_dir = os.path.dirname(current_file)\n", + "print(\"current directory: {}\".format(current_dir))\n", "# Note: in .py files you can get the dir of current file by os.path.dirname(__file__)\n", "\n", - "data_dir = os.path.join(os.path.dirname(current_dir), 'data')\n", - "print('data directory: {}'.format(data_dir))" + "data_dir = os.path.join(os.path.dirname(current_dir), \"data\")\n", + "print(\"data directory: {}\".format(data_dir))" ] }, { @@ -48,9 +48,9 @@ "metadata": {}, "outputs": [], "source": [ - "print('exists: {}'.format(os.path.exists(data_dir)))\n", - "print('is file: {}'.format(os.path.isfile(data_dir)))\n", - "print('is directory: {}'.format(os.path.isdir(data_dir)))" + "print(\"exists: {}\".format(os.path.exists(data_dir)))\n", + "print(\"is file: {}\".format(os.path.isfile(data_dir)))\n", + "print(\"is directory: {}\".format(os.path.isdir(data_dir)))" ] }, { @@ -66,9 +66,9 @@ "metadata": {}, "outputs": [], "source": [ - "file_path = os.path.join(data_dir, 'simple_file.txt')\n", + "file_path = os.path.join(data_dir, \"simple_file.txt\")\n", "\n", - "with open(file_path, 'r') as simple_file:\n", + "with open(file_path, \"r\") as simple_file:\n", " for line in simple_file:\n", " print(line.strip())" ] @@ -90,13 +90,13 @@ "metadata": {}, "outputs": [], "source": [ - "file_path = os.path.join(data_dir, 'simple_file.txt')\n", + "file_path = os.path.join(data_dir, \"simple_file.txt\")\n", "\n", "# THIS IS NOT THE PREFERRED WAY\n", - "simple_file = open(file_path, 'r')\n", + "simple_file = open(file_path, \"r\")\n", "for line in simple_file:\n", " print(line.strip())\n", - "simple_file.close() # This has to be called explicitly " + "simple_file.close() # This has to be called explicitly" ] }, { @@ -112,10 +112,10 @@ "metadata": {}, "outputs": [], "source": [ - "new_file_path = os.path.join(data_dir, 'new_file.txt')\n", + "new_file_path = os.path.join(data_dir, \"new_file.txt\")\n", "\n", - "with open(new_file_path, 'w') as my_file:\n", - " my_file.write('This is my first file that I wrote with Python.')" + "with open(new_file_path, \"w\") as my_file:\n", + " my_file.write(\"This is my first file that I wrote with Python.\")" ] }, { diff --git a/notebooks/beginner/notebooks/classes.ipynb b/notebooks/beginner/notebooks/11_classes.ipynb similarity index 82% rename from notebooks/beginner/notebooks/classes.ipynb rename to notebooks/beginner/notebooks/11_classes.ipynb index b39b340..0eedf2e 100644 --- a/notebooks/beginner/notebooks/classes.ipynb +++ b/notebooks/beginner/notebooks/11_classes.ipynb @@ -18,7 +18,7 @@ " self.name = name\n", "\n", " def greet(self):\n", - " print('Hello {}!'.format(self.name))" + " print(\"Hello {}!\".format(self.name))" ] }, { @@ -27,10 +27,10 @@ "metadata": {}, "outputs": [], "source": [ - "my_instance = MyFirstClass('John Doe')\n", - "print('my_instance: {}'.format(my_instance))\n", - "print('type: {}'.format(type(my_instance)))\n", - "print('my_instance.name: {}'.format(my_instance.name))" + "my_instance = MyFirstClass(\"John Doe\")\n", + "print(\"my_instance: {}\".format(my_instance))\n", + "print(\"type: {}\".format(type(my_instance)))\n", + "print(\"my_instance.name: {}\".format(my_instance.name))" ] }, { @@ -47,7 +47,7 @@ "metadata": {}, "outputs": [], "source": [ - "alice = MyFirstClass(name='Alice')\n", + "alice = MyFirstClass(name=\"Alice\")\n", "alice.greet()" ] }, @@ -67,11 +67,12 @@ "source": [ "class Example:\n", " def __init__(self):\n", - " print('Now we are inside __init__')\n", - " \n", - "print('creating instance of Example')\n", + " print(\"Now we are inside __init__\")\n", + "\n", + "\n", + "print(\"creating instance of Example\")\n", "example = Example()\n", - "print('instance created')" + "print(\"instance created\")" ] }, { @@ -91,13 +92,13 @@ " def __init__(self, var1, var2):\n", " self.first_var = var1\n", " self.second_var = var2\n", - " \n", + "\n", " def print_variables(self):\n", - " print('{} {}'.format(self.first_var, self.second_var))\n", - " \n", - "e = Example('abc', 123)\n", - "e.print_variables()\n", - " " + " print(\"{} {}\".format(self.first_var, self.second_var))\n", + "\n", + "\n", + "e = Example(\"abc\", 123)\n", + "e.print_variables()" ] }, { @@ -118,12 +119,13 @@ " def __init__(self, name, age):\n", " self.name = name\n", " self.age = age\n", - " \n", + "\n", " def __str__(self):\n", - " return 'Person: {}'.format(self.name)\n", - " \n", - "jack = Person('Jack', 82)\n", - "print('This is the string presentation of jack: {}'.format(jack))" + " return \"Person: {}\".format(self.name)\n", + "\n", + "\n", + "jack = Person(\"Jack\", 82)\n", + "print(\"This is the string presentation of jack: {}\".format(jack))" ] }, { @@ -142,28 +144,29 @@ "source": [ "class Example:\n", " # These are class variables\n", - " name = 'Example class'\n", - " description = 'Just an example of a simple class'\n", + " name = \"Example class\"\n", + " description = \"Just an example of a simple class\"\n", "\n", " def __init__(self, var1):\n", " # This is an instance variable\n", " self.instance_variable = var1\n", "\n", " def show_info(self):\n", - " info = 'instance_variable: {}, name: {}, description: {}'.format(\n", - " self.instance_variable, Example.name, Example.description)\n", + " info = \"instance_variable: {}, name: {}, description: {}\".format(\n", + " self.instance_variable, Example.name, Example.description\n", + " )\n", " print(info)\n", "\n", "\n", - "inst1 = Example('foo')\n", - "inst2 = Example('bar')\n", + "inst1 = Example(\"foo\")\n", + "inst2 = Example(\"bar\")\n", "\n", "# name and description have identical values between instances\n", "assert inst1.name == inst2.name == Example.name\n", "assert inst1.description == inst2.description == Example.description\n", "\n", "# If you change the value of a class variable, it's changed across all instances\n", - "Example.name = 'Modified name'\n", + "Example.name = \"Modified name\"\n", "inst1.show_info()\n", "inst2.show_info()" ] @@ -187,7 +190,8 @@ "class Person:\n", " def __init__(self, age):\n", " self._age = age\n", - " \n", + "\n", + "\n", "example_person = Person(age=15)\n", "# You can't do this:\n", "# print(example_person.age)\n", @@ -211,16 +215,17 @@ "class Person:\n", " def __init__(self, age):\n", " self._age = age\n", - " \n", + "\n", " @property\n", " def age(self):\n", " return self._age\n", - " \n", + "\n", + "\n", "example_person = Person(age=15)\n", "# Now you can do this:\n", "print(example_person.age)\n", "# But not this:\n", - "#example_person.age = 16" + "# example_person.age = 16" ] }, { @@ -239,15 +244,16 @@ "class Person:\n", " def __init__(self, age):\n", " self._age = age\n", - " \n", + "\n", " @property\n", " def age(self):\n", " return self._age\n", - " \n", + "\n", " def celebrate_birthday(self):\n", " self._age += 1\n", - " print('Happy bday for {} years old!'.format(self._age))\n", - " \n", + " print(\"Happy bday for {} years old!\".format(self._age))\n", + "\n", + "\n", "example_person = Person(age=15)\n", "example_person.celebrate_birthday()" ] @@ -267,22 +273,22 @@ "source": [ "class Animal:\n", " def greet(self):\n", - " print('Hello, I am an animal')\n", + " print(\"Hello, I am an animal\")\n", "\n", " @property\n", " def favorite_food(self):\n", - " return 'beef'\n", + " return \"beef\"\n", "\n", "\n", "class Dog(Animal):\n", " def greet(self):\n", - " print('wof wof')\n", + " print(\"wof wof\")\n", "\n", "\n", "class Cat(Animal):\n", " @property\n", " def favorite_food(self):\n", - " return 'fish'" + " return \"fish\"" ] }, { @@ -303,7 +309,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -317,7 +323,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.10.3" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/exceptions.ipynb b/notebooks/beginner/notebooks/12_exceptions.ipynb similarity index 82% rename from notebooks/beginner/notebooks/exceptions.ipynb rename to notebooks/beginner/notebooks/12_exceptions.ipynb index 3fe2f0b..94d7268 100644 --- a/notebooks/beginner/notebooks/exceptions.ipynb +++ b/notebooks/beginner/notebooks/12_exceptions.ipynb @@ -34,15 +34,15 @@ "outputs": [], "source": [ "# Let's try to open a file that does not exist\n", - "file_name = 'not_existing.txt'\n", + "file_name = \"not_existing.txt\"\n", "\n", "try:\n", - " with open(file_name, 'r') as my_file:\n", - " print('File is successfully open')\n", - " \n", + " with open(file_name, \"r\") as my_file:\n", + " print(\"File is successfully open\")\n", + "\n", "except FileNotFoundError as e:\n", - " print('Uups, file: {} not found'.format(file_name))\n", - " print('Exception: {} was raised'.format(e))" + " print(\"Uups, file: {} not found\".format(file_name))\n", + " print(\"Exception: {} was raised\".format(e))" ] }, { @@ -60,24 +60,25 @@ "source": [ "def calculate_division(var1, var2):\n", " result = 0\n", - " \n", + "\n", " try:\n", " result = var1 / var2\n", " except ZeroDivisionError as ex1:\n", " print(\"Can't divide by zero\")\n", " except Exception as ex2:\n", - " print('Exception: {}'.format(ex2))\n", + " print(\"Exception: {}\".format(ex2))\n", "\n", " return result\n", "\n", + "\n", "result1 = calculate_division(3, 3)\n", - "print('result1: {}'.format(result1))\n", + "print(\"result1: {}\".format(result1))\n", "\n", - "result2 = calculate_division(3, '3')\n", - "print('result2: {}'.format(result2))\n", + "result2 = calculate_division(3, \"3\")\n", + "print(\"result2: {}\".format(result2))\n", "\n", "result3 = calculate_division(3, 0)\n", - "print('result3: {}'.format(result3))" + "print(\"result3: {}\".format(result3))" ] }, { @@ -96,8 +97,9 @@ "def calculate_division(var1, var2):\n", " return var1 / var2\n", "\n", + "\n", "try:\n", - " result = calculate_division(3, '3')\n", + " result = calculate_division(3, \"3\")\n", "except Exception as e:\n", " print(e)" ] @@ -118,19 +120,23 @@ "source": [ "import math\n", "\n", + "\n", "# Define your own exception\n", "class NegativeNumbersNotSupported(Exception):\n", " pass\n", "\n", + "\n", "# Dummy example how to use your custom exception\n", "def secret_calculation(number1, number2):\n", " if number1 < 0 or number2 < 0:\n", - " msg = 'Negative number in at least one of the parameters: {}, {}'.format(\n", - " number1, number2)\n", + " msg = \"Negative number in at least one of the parameters: {}, {}\".format(\n", + " number1, number2\n", + " )\n", " raise NegativeNumbersNotSupported(msg)\n", "\n", " return math.sqrt(number1) + math.sqrt(number2)\n", "\n", + "\n", "# Uncomment to see the traceback\n", "# result = secret_calculation(-1, 1)" ] @@ -157,4 +163,4 @@ }, "nbformat": 4, "nbformat_minor": 0 -} \ No newline at end of file +} diff --git a/notebooks/beginner/notebooks/modules_and_packages.ipynb b/notebooks/beginner/notebooks/13_modules_and_packages.ipynb similarity index 100% rename from notebooks/beginner/notebooks/modules_and_packages.ipynb rename to notebooks/beginner/notebooks/13_modules_and_packages.ipynb diff --git a/notebooks/beginner/notebooks/debugging.ipynb b/notebooks/beginner/notebooks/14_debugging.ipynb similarity index 95% rename from notebooks/beginner/notebooks/debugging.ipynb rename to notebooks/beginner/notebooks/14_debugging.ipynb index af2e669..57acdc4 100644 --- a/notebooks/beginner/notebooks/debugging.ipynb +++ b/notebooks/beginner/notebooks/14_debugging.ipynb @@ -62,7 +62,7 @@ " self._greet_hawaii(person)\n", " else:\n", " self._greet_polite(person)\n", - " \n", + "\n", " def _greet_polite(self, name):\n", " greeting = \"G'day {}! How are you doing?\".format(name)\n", " print(greeting)\n", @@ -70,14 +70,14 @@ " def _greet_street_style(self, name):\n", " # import pdb; pdb.set_trace() # UNCOMMENT\n", " name = name.upper()\n", - " print('WASSUP {}!?'.format(name))\n", + " print(\"WASSUP {}!?\".format(name))\n", "\n", " def _greet_hawaii(self, name):\n", - " print('Aloha {}!'.format(name))\n", + " print(\"Aloha {}!\".format(name))\n", "\n", "\n", "def main():\n", - " people = ['John Doe', 'Donald', 'Lisa', 'alex']\n", + " people = [\"John Doe\", \"Donald\", \"Lisa\", \"alex\"]\n", " # import pdb; pdb.set_trace() # UNCOMMENT\n", " greeter = SuperGreeter(people)\n", " greeter.greet()\n", diff --git a/notebooks/beginner/notebooks/std_lib.ipynb b/notebooks/beginner/notebooks/15_std_lib.ipynb similarity index 70% rename from notebooks/beginner/notebooks/std_lib.ipynb rename to notebooks/beginner/notebooks/15_std_lib.ipynb index 3818bec..3d13f3b 100644 --- a/notebooks/beginner/notebooks/std_lib.ipynb +++ b/notebooks/beginner/notebooks/15_std_lib.ipynb @@ -24,18 +24,25 @@ "import datetime as dt\n", "\n", "local_now = dt.datetime.now()\n", - "print('local now: {}'.format(local_now))\n", + "print(\"local now: {}\".format(local_now))\n", "\n", "utc_now = dt.datetime.utcnow()\n", - "print('utc now: {}'.format(utc_now))\n", + "print(\"utc now: {}\".format(utc_now))\n", "\n", "# You can access any value separately:\n", - "print('{} {} {} {} {} {}'.format(local_now.year, local_now.month,\n", - " local_now.day, local_now.hour,\n", - " local_now.minute, local_now.second))\n", - "\n", - "print('date: {}'.format(local_now.date()))\n", - "print('time: {}'.format(local_now.time()))" + "print(\n", + " \"{} {} {} {} {} {}\".format(\n", + " local_now.year,\n", + " local_now.month,\n", + " local_now.day,\n", + " local_now.hour,\n", + " local_now.minute,\n", + " local_now.second,\n", + " )\n", + ")\n", + "\n", + "print(\"date: {}\".format(local_now.date()))\n", + "print(\"time: {}\".format(local_now.time()))" ] }, { @@ -52,10 +59,10 @@ "metadata": {}, "outputs": [], "source": [ - "formatted1 = local_now.strftime('%Y/%m/%d-%H:%M:%S')\n", + "formatted1 = local_now.strftime(\"%Y/%m/%d-%H:%M:%S\")\n", "print(formatted1)\n", "\n", - "formatted2 = local_now.strftime('date: %Y-%m-%d time:%H:%M:%S')\n", + "formatted2 = local_now.strftime(\"date: %Y-%m-%d time:%H:%M:%S\")\n", "print(formatted2)" ] }, @@ -73,8 +80,8 @@ "metadata": {}, "outputs": [], "source": [ - "my_dt = dt.datetime.strptime('2000-01-01 10:00:00', '%Y-%m-%d %H:%M:%S')\n", - "print('my_dt: {}'.format(my_dt))" + "my_dt = dt.datetime.strptime(\"2000-01-01 10:00:00\", \"%Y-%m-%d %H:%M:%S\")\n", + "print(\"my_dt: {}\".format(my_dt))" ] }, { @@ -92,12 +99,12 @@ "outputs": [], "source": [ "tomorrow = local_now + dt.timedelta(days=1)\n", - "print('tomorrow this time: {}'.format(tomorrow))\n", + "print(\"tomorrow this time: {}\".format(tomorrow))\n", "\n", "delta = tomorrow - local_now\n", - "print('tomorrow - now = {}'.format(delta))\n", - "print('days: {}, seconds: {}'.format(delta.days, delta.seconds))\n", - "print('total seconds: {}'.format(delta.total_seconds()))" + "print(\"tomorrow - now = {}\".format(delta))\n", + "print(\"days: {}, seconds: {}\".format(delta.days, delta.seconds))\n", + "print(\"total seconds: {}\".format(delta.total_seconds()))" ] }, { @@ -115,6 +122,7 @@ "outputs": [], "source": [ "import sys\n", + "\n", "!{sys.executable} -m pip install pytz" ] }, @@ -128,21 +136,21 @@ "import pytz\n", "\n", "naive_utc_now = dt.datetime.utcnow()\n", - "print('naive utc now: {}, tzinfo: {}'.format(naive_utc_now, naive_utc_now.tzinfo))\n", + "print(\"naive utc now: {}, tzinfo: {}\".format(naive_utc_now, naive_utc_now.tzinfo))\n", "\n", "# Localizing naive datetimes\n", - "UTC_TZ = pytz.timezone('UTC')\n", + "UTC_TZ = pytz.timezone(\"UTC\")\n", "utc_now = UTC_TZ.localize(naive_utc_now)\n", - "print('utc now: {}, tzinfo: {}'.format(utc_now, utc_now.tzinfo))\n", + "print(\"utc now: {}, tzinfo: {}\".format(utc_now, utc_now.tzinfo))\n", "\n", "# Converting localized datetimes to different timezone\n", - "PARIS_TZ = pytz.timezone('Europe/Paris')\n", + "PARIS_TZ = pytz.timezone(\"Europe/Paris\")\n", "paris_now = PARIS_TZ.normalize(utc_now)\n", - "print('Paris: {}, tzinfo: {}'.format(paris_now, paris_now.tzinfo))\n", + "print(\"Paris: {}, tzinfo: {}\".format(paris_now, paris_now.tzinfo))\n", "\n", - "NEW_YORK_TZ = pytz.timezone('America/New_York')\n", + "NEW_YORK_TZ = pytz.timezone(\"America/New_York\")\n", "ny_now = NEW_YORK_TZ.normalize(utc_now)\n", - "print('New York: {}, tzinfo: {}'.format(ny_now, ny_now.tzinfo))" + "print(\"New York: {}, tzinfo: {}\".format(ny_now, ny_now.tzinfo))" ] }, { @@ -171,11 +179,11 @@ "logger = logging.getLogger(__name__)\n", "logger.setLevel(logging.WARNING)\n", "\n", - "logger.debug('This is debug')\n", - "logger.info('This is info')\n", - "logger.warning('This is warning')\n", - "logger.error('This is error')\n", - "logger.critical('This is critical')" + "logger.debug(\"This is debug\")\n", + "logger.info(\"This is info\")\n", + "logger.warning(\"This is warning\")\n", + "logger.error(\"This is error\")\n", + "logger.critical(\"This is critical\")" ] }, { @@ -195,7 +203,7 @@ "try:\n", " path_calculation = 1 / 0\n", "except ZeroDivisionError:\n", - " logging.exception('All went south in my calculation')" + " logging.exception(\"All went south in my calculation\")" ] }, { @@ -215,15 +223,16 @@ "\n", "# This is only required for Jupyter notebook environment\n", "from importlib import reload\n", + "\n", "reload(logging)\n", "\n", - "my_format = '%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s'\n", + "my_format = \"%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s\"\n", "logging.basicConfig(format=my_format)\n", "\n", - "logger = logging.getLogger('MyLogger')\n", + "logger = logging.getLogger(\"MyLogger\")\n", "\n", - "logger.warning('Something bad is going to happen')\n", - "logger.error('Uups, it already happened')" + "logger.warning(\"Something bad is going to happen\")\n", + "logger.error(\"Uups, it already happened\")" ] }, { @@ -244,16 +253,19 @@ "\n", "# This is only required for Jupyter notebook environment\n", "from importlib import reload\n", + "\n", "reload(logging)\n", "\n", - "logger = logging.getLogger('MyFileLogger')\n", + "logger = logging.getLogger(\"MyFileLogger\")\n", "\n", "# Let's define a file_handler for our logger\n", - "log_path = os.path.join(os.getcwd(), 'my_log.txt')\n", + "log_path = os.path.join(os.getcwd(), \"my_log.txt\")\n", "file_handler = logging.FileHandler(log_path)\n", "\n", "# And a nice format\n", - "formatter = logging.Formatter('%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s')\n", + "formatter = logging.Formatter(\n", + " \"%(asctime)s | %(name)-12s | %(levelname)-10s | %(message)s\"\n", + ")\n", "file_handler.setFormatter(formatter)\n", "\n", "logger.addHandler(file_handler)\n", @@ -261,8 +273,8 @@ "# If you want to see it also in the console, add another handler for it\n", "# logger.addHandler(logging.StreamHandler())\n", "\n", - "logger.warning('Oops something is going to happen')\n", - "logger.error('John Doe visits our place')" + "logger.warning(\"Oops something is going to happen\")\n", + "logger.error(\"John Doe visits our place\")" ] }, { @@ -281,10 +293,10 @@ "import random\n", "\n", "rand_int = random.randint(1, 100)\n", - "print('random integer between 1-100: {}'.format(rand_int))\n", + "print(\"random integer between 1-100: {}\".format(rand_int))\n", "\n", "rand = random.random()\n", - "print('random float between 0-1: {}'.format(rand))" + "print(\"random float between 0-1: {}\".format(rand))" ] }, { @@ -331,17 +343,17 @@ "source": [ "import re\n", "\n", - "secret_code = 'qwret 8sfg12f5 fd09f_df'\n", + "secret_code = \"qwret 8sfg12f5 fd09f_df\"\n", "# \"r\" at the beginning means raw format, use it with regular expression patterns\n", - "search_pattern = r'(g12)' \n", + "search_pattern = r\"(g12)\"\n", "\n", "match = re.search(search_pattern, secret_code)\n", - "print('match: {}'.format(match))\n", - "print('match.group(): {}'.format(match.group()))\n", + "print(\"match: {}\".format(match))\n", + "print(\"match.group(): {}\".format(match.group()))\n", "\n", - "numbers_pattern = r'[0-9]'\n", + "numbers_pattern = r\"[0-9]\"\n", "numbers_match = re.findall(numbers_pattern, secret_code)\n", - "print('numbers: {}'.format(numbers_match))" + "print(\"numbers: {}\".format(numbers_match))" ] }, { @@ -359,21 +371,23 @@ "source": [ "import re\n", "\n", + "\n", "def validate_only_lower_case_letters(to_validate):\n", - " pattern = r'^[a-z]+$'\n", + " pattern = r\"^[a-z]+$\"\n", " return bool(re.match(pattern, to_validate))\n", "\n", - "print(validate_only_lower_case_letters('thisshouldbeok'))\n", - "print(validate_only_lower_case_letters('thisshould notbeok'))\n", - "print(validate_only_lower_case_letters('Thisshouldnotbeok'))\n", - "print(validate_only_lower_case_letters('thisshouldnotbeok1'))\n", - "print(validate_only_lower_case_letters(''))" + "\n", + "print(validate_only_lower_case_letters(\"thisshouldbeok\"))\n", + "print(validate_only_lower_case_letters(\"thisshould notbeok\"))\n", + "print(validate_only_lower_case_letters(\"Thisshouldnotbeok\"))\n", + "print(validate_only_lower_case_letters(\"thisshouldnotbeok1\"))\n", + "print(validate_only_lower_case_letters(\"\"))" ] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -387,7 +401,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.10.3" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/testing2.ipynb b/notebooks/beginner/notebooks/16_testing2.ipynb similarity index 88% rename from notebooks/beginner/notebooks/testing2.ipynb rename to notebooks/beginner/notebooks/16_testing2.ipynb index f4c18e0..d0e72e2 100644 --- a/notebooks/beginner/notebooks/testing2.ipynb +++ b/notebooks/beginner/notebooks/16_testing2.ipynb @@ -16,12 +16,14 @@ "# Let's make sure pytest and ipytest packages are installed\n", "# ipytest is required for running pytest inside Jupyter notebooks\n", "import sys\n", + "\n", "!{sys.executable} -m pip install pytest\n", "!{sys.executable} -m pip install ipytest\n", "\n", - "import ipytest.magics\n", - "import pytest\n", - "__file__ = 'testing2.ipynb'" + "# These are needed for running pytest inside Jupyter notebooks\n", + "import ipytest\n", + "\n", + "ipytest.autoconfig()" ] }, { @@ -44,18 +46,18 @@ " self.first_name = first_name\n", " self.last_name = last_name\n", " self.age = age\n", - " \n", + "\n", " @property\n", " def full_name(self):\n", - " return '{} {}'.format(self.first_name, self.last_name)\n", - " \n", + " return \"{} {}\".format(self.first_name, self.last_name)\n", + "\n", " @property\n", " def as_dict(self):\n", - " return {'name': self.full_name, 'age': self.age}\n", - " \n", + " return {\"name\": self.full_name, \"age\": self.age}\n", + "\n", " def increase_age(self, years):\n", " if years < 0:\n", - " raise ValueError('Can not make people younger :(')\n", + " raise ValueError(\"Can not make people younger :(\")\n", " self.age += years" ] }, @@ -73,9 +75,12 @@ "outputs": [], "source": [ "# This would be in either conftest.py or test_person.py\n", + "import pytest\n", + "\n", + "\n", "@pytest.fixture()\n", "def default_person():\n", - " person = Person(first_name='John', last_name='Doe', age=82)\n", + " person = Person(first_name=\"John\", last_name=\"Doe\", age=82)\n", " return person" ] }, @@ -92,7 +97,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean]\n", + "%%ipytest\n", "\n", "# These would be in test_person.py\n", "def test_full_name(default_person): # Note: we use fixture as an argument of the test case\n", @@ -147,7 +152,7 @@ " \"\"\"Replaces names (uppercase words) of original_str by new_name\"\"\"\n", " words = original_str.split()\n", " manipulated_words = [new_name if w.istitle() else w for w in words]\n", - " return ' '.join(manipulated_words)" + " return \" \".join(manipulated_words)" ] }, { @@ -163,7 +168,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean]\n", + "%%ipytest\n", "\n", "# This would be in your test module\n", "@pytest.mark.parametrize(\"original,new_name,expected\", [\n", @@ -175,11 +180,18 @@ " result = replace_names(original, new_name)\n", " assert result == expected" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -193,7 +205,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.10.3" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/venv.ipynb b/notebooks/beginner/notebooks/17_venv.ipynb similarity index 100% rename from notebooks/beginner/notebooks/venv.ipynb rename to notebooks/beginner/notebooks/17_venv.ipynb diff --git a/notebooks/beginner/notebooks/project_structure.ipynb b/notebooks/beginner/notebooks/18_project_structure.ipynb similarity index 96% rename from notebooks/beginner/notebooks/project_structure.ipynb rename to notebooks/beginner/notebooks/18_project_structure.ipynb index f3b0878..823e966 100644 --- a/notebooks/beginner/notebooks/project_structure.ipynb +++ b/notebooks/beginner/notebooks/18_project_structure.ipynb @@ -33,7 +33,7 @@ "\n", "\n", "def magical_function():\n", - " LOGGER.warning('We are about to do some magical stuff')\n", + " LOGGER.warning(\"We are about to do some magical stuff\")\n", "\n", "\n", "def main():\n", @@ -41,7 +41,7 @@ " magical_function()\n", "\n", "\n", - "if __name__ == '__main__':\n", + "if __name__ == \"__main__\":\n", " main()" ] }, diff --git a/notebooks/intermediate/exercises/std_lib2_exercise.ipynb b/notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb similarity index 82% rename from notebooks/intermediate/exercises/std_lib2_exercise.ipynb rename to notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb index 163ce02..072d73a 100644 --- a/notebooks/intermediate/exercises/std_lib2_exercise.ipynb +++ b/notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb @@ -20,8 +20,9 @@ "source": [ "from urllib.request import urlopen\n", "\n", + "\n", "def get_wiki_article(name):\n", - " url = 'https://en.wikipedia.org/wiki/%7B%7D'.format(name)\n", + " url = \"https://en.wikipedia.org/wiki/%7B%7D/".format(name)\n", " response = urlopen(url)\n", " content = str(response.read())\n", " return content" @@ -33,7 +34,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Your implementation here\n" + "# Your implementation here" ] }, { @@ -51,13 +52,15 @@ }, "outputs": [], "source": [ - "article = 'Python_(programming_language)'\n", + "article = \"Python_(programming_language)\"\n", "res = get_wiki_article(article)\n", - "assert 'Guido van Rossum' not in res, 'Guido is still there!'\n", - "assert res == 'Python is cool!'\n", - "urlopen.assert_called_with('https://en.wikipedia.org/wiki/Python_(programming_language)')\n", + "assert \"Guido van Rossum\" not in res, \"Guido is still there!\"\n", + "assert res == \"Python is cool!\"\n", + "urlopen.assert_called_with(\n", + " \"https://en.wikipedia.org/wiki/Python_(programming_language)/"\n", + ")\n", "\n", - "print('All good!')" + "print(\"All good!\")" ] }, { @@ -99,18 +102,18 @@ }, "outputs": [], "source": [ - "car1 = Car(25000, 2000, 'BMW')\n", + "car1 = Car(25000, 2000, \"BMW\")\n", "assert car1.price == 25000\n", "assert car1.mileage == 2000\n", - "assert car1.brand == 'BMW'\n", + "assert car1.brand == \"BMW\"\n", "assert isinstance(car1, tuple)\n", "\n", "# Note that indexing works also!\n", "# This means that if you change a tuple into a namedtuple,\n", "# the change will be backwards compatible.\n", - "assert car1[2] == 'BMW'\n", + "assert car1[2] == \"BMW\"\n", "\n", - "print('All good!')" + "print(\"All good!\")" ] }, { @@ -149,7 +152,7 @@ }, "outputs": [], "source": [ - "VOWELS = ('a', 'e', 'i', 'o', 'u')" + "VOWELS = (\"a\", \"e\", \"i\", \"o\", \"u\")" ] }, { @@ -177,35 +180,22 @@ }, "outputs": [], "source": [ - "names = ('Alice', 'John', 'Lisa', 'John', 'Eric', 'Waldo', 'annie', 'Alice', 'John')\n", + "names = (\"Alice\", \"John\", \"Lisa\", \"John\", \"Eric\", \"Waldo\", \"annie\", \"Alice\", \"John\")\n", "expected = {\n", - " 'consonant': {\n", - " 'John': 3,\n", - " 'Waldo': 1,\n", - " 'Lisa': 1\n", - " },\n", - " 'vowel': {\n", - " 'Alice': 2,\n", - " 'annie': 1,\n", - " 'Eric': 1\n", - " }\n", + " \"consonant\": {\"John\": 3, \"Waldo\": 1, \"Lisa\": 1},\n", + " \"vowel\": {\"Alice\": 2, \"annie\": 1, \"Eric\": 1},\n", "}\n", "assert name_mapping(names) == expected\n", - "print('First ok!')\n", + "print(\"First ok!\")\n", "\n", - "only_consonants = ('John', 'Doe', 'Doe')\n", - "expected2 = {\n", - " 'consonant': {\n", - " 'John': 1,\n", - " 'Doe': 2\n", - " }\n", - "}\n", + "only_consonants = (\"John\", \"Doe\", \"Doe\")\n", + "expected2 = {\"consonant\": {\"John\": 1, \"Doe\": 2}}\n", "assert name_mapping(only_consonants) == expected2\n", - "print('Second ok!')\n", + "print(\"Second ok!\")\n", "\n", "assert name_mapping([]) == {}\n", "\n", - "print('All ok!')" + "print(\"All ok!\")" ] } ], diff --git a/notebooks/intermediate/exercises/idiomatic_python_exercise.ipynb b/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb similarity index 87% rename from notebooks/intermediate/exercises/idiomatic_python_exercise.ipynb rename to notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb index a17da86..e1776c3 100644 --- a/notebooks/intermediate/exercises/idiomatic_python_exercise.ipynb +++ b/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb @@ -84,7 +84,7 @@ " 2. numeric values (list of floats)\n", " 3. non-numeric values (list of strings)\n", " \"\"\"\n", - " data_file = open(path, 'r')\n", + " data_file = open(path, \"r\")\n", " lines = data_file.readlines()\n", " line_count = len(lines)\n", " idx = 0\n", @@ -94,7 +94,7 @@ " while idx < line_count:\n", " line = lines[idx]\n", " line = line.strip()\n", - " if line == '':\n", + " if line == \"\":\n", " empty_lines = empty_lines + 1\n", " else:\n", " is_number = False\n", @@ -129,20 +129,28 @@ " most_common_words = most_common_info[0]\n", " most_common_count = most_common_info[1]\n", "\n", - " most_common_str = ''\n", + " most_common_str = \"\"\n", " for idx in range(len(most_common_words)):\n", - " most_common_str += most_common_words[idx] + ', '\n", + " most_common_str += most_common_words[idx] + \", \"\n", " # remove the last comma and space\n", - " most_common_str = most_common_str[0:len(most_common_str) - 2]\n", - "\n", - " report = ('missing values: {}\\n'\n", - " 'highest number: {}\\n'\n", - " 'most common words: {}\\n'\n", - " 'occurrences of most common: {}\\n'\n", - " '#####\\n'\n", - " 'numbers: {}\\n'\n", - " 'words: {}').format(missing_values, max_value, most_common_str,\n", - " most_common_count, numbers, lower_case_words)\n", + " most_common_str = most_common_str[0 : len(most_common_str) - 2]\n", + "\n", + " report = (\n", + " \"missing values: {}\\n\"\n", + " \"highest number: {}\\n\"\n", + " \"most common words: {}\\n\"\n", + " \"occurrences of most common: {}\\n\"\n", + " \"#####\\n\"\n", + " \"numbers: {}\\n\"\n", + " \"words: {}\"\n", + " ).format(\n", + " missing_values,\n", + " max_value,\n", + " most_common_str,\n", + " most_common_count,\n", + " numbers,\n", + " lower_case_words,\n", + " )\n", "\n", " return report\n", "\n", @@ -234,9 +242,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Your beautiful refactored, idiomatic, pythonic solution here\n", - "\n", - "\n" + "# Your beautiful refactored, idiomatic, pythonic solution here" ] }, { @@ -257,44 +263,44 @@ "import os\n", "\n", "CURRENT_DIR = os.getcwd()\n", - "DATA_DIR = os.path.join(os.path.dirname(CURRENT_DIR), 'data')\n", + "DATA_DIR = os.path.join(os.path.dirname(CURRENT_DIR), \"data\")\n", "\n", - "DATA_FILE1 = os.path.join(DATA_DIR, 'misc_data1.txt')\n", - "DATA_FILE2 = os.path.join(DATA_DIR, 'misc_data2.txt')\n", - "DATA_FILE3 = os.path.join(DATA_DIR, 'empty.txt')\n", + "DATA_FILE1 = os.path.join(DATA_DIR, \"misc_data1.txt\")\n", + "DATA_FILE2 = os.path.join(DATA_DIR, \"misc_data2.txt\")\n", + "DATA_FILE3 = os.path.join(DATA_DIR, \"empty.txt\")\n", "\n", - "expected1 = '''missing values: 2\n", + "expected1 = \"\"\"missing values: 2\n", "highest number: 99.0\n", "most common words: john\n", "occurrences of most common: 4\n", "#####\n", "numbers: [1.0, 2.0, 99.0, 6.72, 2.0, 2.0, 2.0]\n", - "words: ['john', 'doe', 'john', 'john', 'was', 'here', 'this', 'is', 'totally', 'random', 'john']'''\n", + "words: ['john', 'doe', 'john', 'john', 'was', 'here', 'this', 'is', 'totally', 'random', 'john']\"\"\"\n", "\n", - "expected2 = '''missing values: 3\n", + "expected2 = \"\"\"missing values: 3\n", "highest number: 101.0\n", "most common words: doe, john\n", "occurrences of most common: 4\n", "#####\n", "numbers: [1.0, 2.0, 101.0, 6.72, 2.0, 2.0, 67.0, 2.0]\n", - "words: ['john', 'doe', 'john', 'john', 'doe', 'was', 'doe', 'here', 'this', 'is', 'totally', 'random', 'john', 'doe']'''\n", + "words: ['john', 'doe', 'john', 'john', 'doe', 'was', 'doe', 'here', 'this', 'is', 'totally', 'random', 'john', 'doe']\"\"\"\n", "\n", - "expected3 = '''missing values: 0\n", + "expected3 = \"\"\"missing values: 0\n", "highest number: None\n", "most common words: \n", "occurrences of most common: 0\n", "#####\n", "numbers: []\n", - "words: []'''\n", + "words: []\"\"\"\n", "\n", "assert get_report(DATA_FILE1) == expected1\n", - "print('First one OK!')\n", + "print(\"First one OK!\")\n", "\n", "assert get_report(DATA_FILE2) == expected2\n", - "print('Second one OK!')\n", + "print(\"Second one OK!\")\n", "\n", "assert get_report(DATA_FILE3) == expected3\n", - "print('All OK, woop woop!')" + "print(\"All OK, woop woop!\")" ] }, { diff --git a/notebooks/intermediate/html/01_best_practices.html b/notebooks/intermediate/html/01_best_practices.html new file mode 100644 index 0000000..9c4f31f --- /dev/null +++ b/notebooks/intermediate/html/01_best_practices.html @@ -0,0 +1,15945 @@ + + + + + +01_best_practices + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/intermediate/html/01_idiomatic_loops.html b/notebooks/intermediate/html/01_idiomatic_loops.html new file mode 100644 index 0000000..88d9f9d --- /dev/null +++ b/notebooks/intermediate/html/01_idiomatic_loops.html @@ -0,0 +1,16013 @@ + + + + + +01_idiomatic_loops + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/intermediate/html/01_pytest_fixtures.html b/notebooks/intermediate/html/01_pytest_fixtures.html new file mode 100644 index 0000000..49503dc --- /dev/null +++ b/notebooks/intermediate/html/01_pytest_fixtures.html @@ -0,0 +1,15902 @@ + + + + + +01_pytest_fixtures + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/intermediate/html/01_std_lib2.html b/notebooks/intermediate/html/01_std_lib2.html new file mode 100644 index 0000000..62d537a --- /dev/null +++ b/notebooks/intermediate/html/01_std_lib2.html @@ -0,0 +1,15788 @@ + + + + + +01_std_lib2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/intermediate/html/02_idiomatic_dicts.html b/notebooks/intermediate/html/02_idiomatic_dicts.html new file mode 100644 index 0000000..8491e8f --- /dev/null +++ b/notebooks/intermediate/html/02_idiomatic_dicts.html @@ -0,0 +1,15879 @@ + + + + + +02_idiomatic_dicts + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/intermediate/html/03_idiomatic_misc1.html b/notebooks/intermediate/html/03_idiomatic_misc1.html new file mode 100644 index 0000000..1027480 --- /dev/null +++ b/notebooks/intermediate/html/03_idiomatic_misc1.html @@ -0,0 +1,16410 @@ + + + + + +03_idiomatic_misc1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/intermediate/html/04_idiomatic_misc2.html b/notebooks/intermediate/html/04_idiomatic_misc2.html new file mode 100644 index 0000000..17f35c6 --- /dev/null +++ b/notebooks/intermediate/html/04_idiomatic_misc2.html @@ -0,0 +1,16268 @@ + + + + + +04_idiomatic_misc2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/notebooks/intermediate/html/best_practices.html b/notebooks/intermediate/html/best_practices.html deleted file mode 100644 index 2803cb6..0000000 --- a/notebooks/intermediate/html/best_practices.html +++ /dev/null @@ -1,12473 +0,0 @@ - - - -tmp_best_practices - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Best practices in development

-
-
-
-
-
-
-
-

One virtual environment per project

- -
-
-
-
-
-
-
-

Why

    -
  • Isolation
  • -
  • Different projects have different dependency versions
  • -
  • You don't want to mess up the system Python
  • -
- -
-
-
-
-
-
-
-

Tooling

pipenv is currently the recommended tool for dependency management but "consider other tools such as pip when pipenv does not meet your use case". If pipenv doesn't fit your use case, I recommend using virtualenvwrapper for managing virtual environments and pip for package management. On the other hand, if you're working on only a couple of projects, built-in venv will do just fine.

-

pipenv

- -
-
-
-
-
-
-
-

virtualenvwrapper

    -
  • If you are using Windows command prompt: virtualenvwrapper-win
  • -
  • Like the name suggests, a wrapper around virtualenv
  • -
  • Eases the workflow for creating, deleting, and (de)activating your virtual environments
  • -
- -
-
-
-
-
-
-
-

pyenv

    -
  • Easily change global / per project Python version
  • -
  • Also a tool for installing different Python versions (also different runtimes available, e.g. PyPy)
  • -
  • Useful if you'll need to work with different Python versions
  • -
- -
-
-
-
-
-
-
-

Test your code

- -
-
-
-
-
-
-
-

Why

    -
  • No surprises (especially in production)
  • -
  • Make sure that everything works as expected
  • -
  • Make sure that old stuff works as expected after introducing new features (regression)
  • -
  • Tests give you confidence while refactoring
  • -
  • Good tests demonstrate the use cases of application, i.e. they also document the implementation
  • -
  • ...
  • -
- -
-
-
-
-
-
-
-

Tooling

pytest

There's unittest module in Python Standard Library but the go-to test runner nowadays is definitely pytest.

-

Some reasons to use pytest:

- - -
-
-
-
-
-
-
-

tox

tox makes it simple to test your code against different Python interpreter/runtime and dependency versions. This is important when you're writing software which should support different Python versions, which is usually the case with library-like packages. On the other hand, if you're developing, say, a web application which will be deployed to a known target platform, testing against multiple different versions is usually not necessary. However, tox makes it also possible to configure, for example, linting as part of tox run. Thus, tox may simplify the development workflow significantly by wrapping multiple different operations under a single command.

- -
-
-
-
-
-
-
-

Write high quality code

- -
-
-
-
-
-
-
-

Why

    -
  • Easy to read
  • -
  • Better maintainability
  • -
  • Better quality == less bugs
  • -
- -
-
-
-
-
-
In [1]:
-
-
-
import this
-
- -
-
-
- -
-
- - -
- -
- - -
-
The Zen of Python, by Tim Peters
-
-Beautiful is better than ugly.
-Explicit is better than implicit.
-Simple is better than complex.
-Complex is better than complicated.
-Flat is better than nested.
-Sparse is better than dense.
-Readability counts.
-Special cases aren't special enough to break the rules.
-Although practicality beats purity.
-Errors should never pass silently.
-Unless explicitly silenced.
-In the face of ambiguity, refuse the temptation to guess.
-There should be one-- and preferably only one --obvious way to do it.
-Although that way may not be obvious at first unless you're Dutch.
-Now is better than never.
-Although never is often better than *right* now.
-If the implementation is hard to explain, it's a bad idea.
-If the implementation is easy to explain, it may be a good idea.
-Namespaces are one honking great idea -- let's do more of those!
-
-
-
- -
-
- -
-
-
-
-
-

Tooling - code formatters

PEP8 (see also "for humans version") describes the style guidelines for Python code, you should follow them. Luckily, there are awesome tools that handle this for you while you focus on writing code, not formatting it.

- -
-
-
-
-
-
-
-

yapf

- -
-
-
-
-
-
-
-

black

    -
  • Note requires Python 3.6+
  • -
  • Note "This is a beta product" while writing this
  • -
  • Uncompromising - not as many configuration options as in yapf
  • -
  • Good integration with editors
  • -
  • Try it in the playground
  • -
- -
-
-
-
-
-
-
-

Tooling - linters

Automatic code formatting is great but in addition to that, you should use static analyzer (linter) to detect potential pitfalls in your code.

- -
-
-
-
-
-
-
-

flake8

- -
-
-
-
-
-
-
-

pylint

    -
  • More verbose compared to flake8
  • -
  • Criticized about the default configuration but is easily configurable
  • -
  • Gives an overall score
  • -
- -
-
-
-
-
-
-
-

bandit

    -
  • Checks for security vulnerabilities
  • -
- -
-
-
-
-
-
-
-

Tooling - pre-commit

pre-commit

Ideally, all project contributors should follow the best practices of the project, let it be e.g. respecting PEP8 or making sure there's no linting errors or security vulnerabilities in their change sets. However, as code formatters and linters are (mainly) local tools, this can not be guaranteed. pre-commit let's you configure (.pre-commit-config.yaml file) a set of hooks that will be run as pre actions to a commit/push. After a developer has called once pre-commit install, these hooks will be then automatically ran prior each commit/push.

-
    -
  • Run formatting before commit
  • -
  • Fail the commit in case linting errors
  • -
  • Even exercise the test suite before the code ends up to remote (might be time consuming in most scenarios though)
  • -
  • Easy to configure your own hooks
  • -
  • And use the existing ones
  • -
  • There's also pre-push option
  • -
  • Written in Python but supports also other languages, such as Ruby, Go, and Rust
  • -
  • Less failed CI builds!
  • -
- -
-
-
-
-
-
-
-

Structure your code and projects

- -
-
-
-
-
-
-
-

Why

    -
  • Package and module structure gives an overview about the project
  • -
  • Modular design == better reusability
  • -
- -
-
-
-
-
-
-
-

How

Some general guidelines:

-
    -
  • Don't put too much stuff into one module
  • -
  • Split project into packages
  • -
  • Be consistent with your naming conventions
  • -
- -
-
-
-
-
-
-
-

A few words about structuring your projects. If you're developing, say, a relative big business application, it makes sense to separate some of the non-core business logic packages into a separate project and publish that as separate package. This way the "main" repository doesn't get bloated and it's more approachable for newcomers. Additionally, there's a change that you (or someone else) can easily reuse this "separated" package in the future, which is often the case e.g. for different kinds of utility functionalities.

-

Let's take a practical example. If your team has two different applications which interact with the same third party, it's beneficial to implement a separate client library for communication with it. This way a change is needed only in one place (in the client library) if the third party decides to make a backwards incompatible change in their API.

- -
-
-
-
-
-
-
-

Tooling

cookiecutter

- -
-
-
-
-
-
-
-

Cookiecutter is a tool which let's you create projects from predefined templates.

-
    -
  • Rapid set-up of new projects, no need to copy paste from existing ones
  • -
  • Consistent development practices across all projects (project structure as well as e.g. pre-commit, tox, and CI configuration)
  • -
  • You can create one yourself or use some of the existing ones
  • -
  • Written in Python but is applicable for non-Python projects as well, even non-programming related directory and file structures
  • -
- -
-
-
-
-
-
-
-

Use continuous integration and deployment

- -
-
-
-
-
-
-
-

CI & CD belong to the best practices of software development without controversy, no matter what is the technology stack used for development. From Python point of view, CI is the place where we want to make sure that the other best practices described above are followed. For example, in bigger projects, it may not be even practical/possible to run the full test suite on developer's machine.

- -
-
-
-
-
-
-
-

Why

    -
  • Make sure the tests pass
  • -
  • CI is the place where it's possible to run also some time consuming tests which the impatient developers prefer to skip on their local machines
  • -
  • Make sure there's no linting errors
  • -
  • Ideally, the place to test against all target versions and platforms
  • -
  • Overall, CI is the last resort for automatically ensuring the quality
  • -
  • Manual deployments are time consuming and error-prone, CD is automated and deterministic
  • -
  • You want to automate as much as possible, human time is expensive
  • -
  • Minimize the time required for code reviews - what could be detected with automatic tools, should be detected by using those tools. Human time is expensive.
  • -
- -
-
-
-
-
-
-
-

Tooling

Tooling depends on which git repository manager option you've chosen and what kind of requirements you have. For example:

- - -
-
-
-
-
-
-
-

Utilize the capabitilies of your editor

-
-
-
-
-
-
-
-

Why

    -
  • Efficient and fluent development
  • -
  • There's plenty of tools to make your daily programming easier, why would you not use them
  • -
- -
-
-
-
-
-
-
-

Tooling

As there's a number of different editors and IDEs available, not to mention that everyone has their own preferences, I'll just focus on highlighting some of the features of my favorite IDE, PyCharm, which I highly recommend for Python development.

-

PyCharm

    -
  • Good integration with pytest, e.g. run single tests / test classes / test modules
  • -
  • Git integration (in case you don't like command line)
  • -
  • Easy to configure to use automatic formatting, e.g black
  • -
  • Intuitive searching capabilities
  • -
  • Refactoring features
  • -
  • Debugger
  • -
  • Jupyter Notebook integration
  • -
  • Free community edition already contains all you need
  • -
- -
-
-
-
-
-
-
-

Use existing solutions

- -
-
-
-
-
-
-
-

Why

    -
  • Python Standard Library is extensive - and stable!
  • -
  • There are over 150k packages in PyPI
  • -
  • Someone has most likely solved the problem you're trying to solve
  • -
  • Spend 5 minutes doing a google research before starting to solve a new problem, e.g. stackoverflow is a magical place.
  • -
- -
-
-
-
-
-
-
-

Learn how to debug efficiently

- -
-
-
-
-
-
-
-

Why

    -
  • You won't write completely stable code anyway - impossible looking conditions will occur.
  • -
  • When something is not working as expected, there are plenty of tools out there to help you figure out what's going on.
  • -
- -
-
-
-
-
-
-
-

Tooling - debuggers

pdb

    -
  • Part of the Standard Library
  • -
  • Sufficient for most use cases
  • -
- -
-
-
-
-
-
-
-

ipdb

    -
  • Feature rich pdb with similar API
  • -
- -
-
-
-
-
-
-
-

pdb++

    -
  • Drop-in replacement for pdb with additional features
  • -
- -
-
-
-
-
-
-
-

Tooling - profilers

-
-
-
-
-
-
-
-

gprof2dot

    -
  • Find the performance bottlenecks of your application via illustrative graphs
  • -
  • If you're using pytest (like you should), see also pytest-profiling which is powered by gprof2dot
  • -
- -
-
-
-
-
-
-
-

py-spy

    -
  • Profile running Python program without the need for modifying the source code or restarting the target process
  • -
  • Potential tool for identifying problems of e.g. a web application in production
  • -
- -
-
-
-
-
-
-
-

objgraph

    -
  • Graphs which are useful while hunting memory leaks
  • -
- -
-
-
-
-
-
-
-

Tooling - runtime error tracking

These are especially useful with web applications as you'll get reports - and notifications - of runtime exceptions with full tracebacks and variable values. This information is often enough for identifying the root cause of the problem, which is a huge benefit considering the time required for implementing and deploying the fix.

- -
-
-
-
-
-
-
-

Sentry

    -
  • Complete stack traces with relevant variable (locals()) values
  • -
  • Browser and OS information of the client
  • -
  • Support for other languages as well
  • -
- -
-
-
-
-
-
-
-

rollbar

    -
  • Very similar to sentry
  • -
- -
-
-
-
-
-
-
-

While writing this, both sentry and rollbar are free for hobbyist use.

- -
-
-
-
-
-
-
-

Tooling - misc

-
-
-
-
-
-
-
-

Use logging instead of prints

- -
-
-
-
-
-
-
-
    -
  • logging is part of the Standard Library
  • -
  • With logging you can redirect the output to a file
  • -
  • Logs are usually the first place to look at after an end user reports an issue
  • -
  • You can specify the runtime level - no need to remove the debug prints
  • -
- -
-
-
-
-
-
-
-

General guidelines

    -
  • Use Python 3, legacy Python (aka 2.7) will retire soon
  • -
  • Develop in branches. Even if you're the only person in the project, branching makes it possible to easily switch between different features / bug fixes.
  • -
  • If you're not developing alone, practice code reviews. It's one of the best ways to learn for both parties.
  • -
  • Document your master pieces
  • -
- -
-
-
-
-
- - - - - - diff --git a/notebooks/intermediate/html/idiomatic_dicts.html b/notebooks/intermediate/html/idiomatic_dicts.html deleted file mode 100644 index e9b6335..0000000 --- a/notebooks/intermediate/html/idiomatic_dicts.html +++ /dev/null @@ -1,12431 +0,0 @@ - - - -tmp_idiomatic_dicts - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Idiomatic dictionaries

-
-
-
-
-
-
-
-

get - default value of a non existing key while accessing

Especially handy if you're unsure about the presence of a key.

- -
-
-
-
-
-
In [1]:
-
-
-
my_dict = {'a': 1, 'b': 2, 'c': 3}
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [2]:
-
-
-
if 'g' in my_dict:
-    value = my_dict['g']
-else:
-    value = 'some default value'
-print(value)
-
- -
-
-
- -
-
- - -
- -
- - -
-
some default value
-
-
-
- -
-
- -
-
-
-
-
-

Or like this.

- -
-
-
-
-
-
In [3]:
-
-
-
try:
-    value = my_dict['g']
-except KeyError:
-    value = 'some default value'
-print(value)
-
- -
-
-
- -
-
- - -
- -
- - -
-
some default value
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [4]:
-
-
-
value = my_dict.get('g', 'some default value')
-print(value)
-
- -
-
-
- -
-
- - -
- -
- - -
-
some default value
-
-
-
- -
-
- -
-
-
-
-
-

Note that if you don't provide the default value for get, the return value will be None if the key is not present in the dictionary

- -
-
-
-
-
-
In [5]:
-
-
-
value = my_dict.get('g')
-print(value is None)
-
- -
-
-
- -
-
- - -
- -
- - -
-
True
-
-
-
- -
-
- -
-
-
-
-
-

setdefault - same as get but also sets the value if not present

-
-
-
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [6]:
-
-
-
my_dict = {'a': 1, 'b': 2, 'c': 3}
-
-key = 'g'
-if key in my_dict:
-    value = my_dict[key]
-else:
-    value = 'some default value'
-    my_dict[key] = value
-    
-print(value)
-print(my_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
some default value
-{'g': 'some default value', 'c': 3, 'b': 2, 'a': 1}
-
-
-
- -
-
- -
-
-
-
-
-

Let's do it like this!

-
-
-
-
-
-
In [7]:
-
-
-
my_dict = {'a': 1, 'b': 2, 'c': 3}
-
-key = 'g'
-value = my_dict.setdefault(key, 'some default value')
-
-print(value)
-print(my_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
some default value
-{'g': 'some default value', 'c': 3, 'b': 2, 'a': 1}
-
-
-
- -
-
- -
-
-
-
-
-

Comprehensions

Let's say we have a collection of numbers and we want to store those as a dictionary where the number is key and it's square is the value.

- -
-
-
-
-
-
In [8]:
-
-
-
numbers = (1, 5, 10)
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [9]:
-
-
-
squares = {}
-for num in numbers:
-    squares[num] = num**2
-print(squares)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{1: 1, 10: 100, 5: 25}
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [10]:
-
-
-
squares = {num: num**2 for num in numbers}
-print(squares)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{1: 1, 10: 100, 5: 25}
-
-
-
- -
-
- -
-
-
-
-
-

Another example

-
-
-
-
-
-
In [11]:
-
-
-
keys = ('a', 'b', 'c')
-values = [True, 100, 'John Doe']
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [12]:
-
-
-
my_dict = {}
-for idx, key in enumerate(keys):
-    my_dict[key] = values[idx]
-print(my_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'c': 'John Doe', 'b': 100, 'a': True}
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [13]:
-
-
-
my_dict = {k: v for k, v in zip(keys, values)}
-print(my_dict)
-
-# Or even like this:
-my_dict2 = dict(zip(keys, values))
-
-assert my_dict2 == my_dict
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'c': 'John Doe', 'b': 100, 'a': True}
-
-
-
- -
-
- -
-
-
-
-
-

Looping

-
-
-
-
-
-
In [14]:
-
-
-
my_dict = {'age': 83, 'is gangster': True, 'name': 'John Doe'}
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [15]:
-
-
-
for key in my_dict:
-    val = my_dict[key]
-    print('key: {:15s} value: {}'.format(key, val))
-
- -
-
-
- -
-
- - -
- -
- - -
-
key: is gangster     value: True
-key: age             value: 83
-key: name            value: John Doe
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [16]:
-
-
-
for key, val in my_dict.items():
-    print('key: {:15s} value: {}'.format(key, val))
-
- -
-
-
- -
-
- - -
- -
- - -
-
key: is gangster     value: True
-key: age             value: 83
-key: name            value: John Doe
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/intermediate/html/idiomatic_loops.html b/notebooks/intermediate/html/idiomatic_loops.html deleted file mode 100644 index 9e704b3..0000000 --- a/notebooks/intermediate/html/idiomatic_loops.html +++ /dev/null @@ -1,12544 +0,0 @@ - - - -tmp_idiomatic_loops - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Idiomatic loops

-
-
-
-
-
-
-
-

Looping in general

-
-
-
-
-
-
In [1]:
-
-
-
data = ['John', 'Doe', 'was', 'here']
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this. While loops are actually really rarely needed.

- -
-
-
-
-
-
In [2]:
-
-
-
idx = 0
-while idx < len(data):
-    print(data[idx])
-    idx += 1
-
- -
-
-
- -
-
- - -
- -
- - -
-
John
-Doe
-was
-here
-
-
-
- -
-
- -
-
-
-
-
-

Don't do like this either.

- -
-
-
-
-
-
In [3]:
-
-
-
for idx in range(len(data)):
-    print(data[idx])
-
- -
-
-
- -
-
- - -
- -
- - -
-
John
-Doe
-was
-here
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [4]:
-
-
-
for item in data:
-    print(item)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John
-Doe
-was
-here
-
-
-
- -
-
- -
-
-
-
-
-

If you need the index as well, you can use enumerate.

- -
-
-
-
-
-
In [5]:
-
-
-
for idx, val in enumerate(data):
-    print('{}: {}'.format(idx, val))
-
- -
-
-
- -
-
- - -
- -
- - -
-
0: John
-1: Doe
-2: was
-3: here
-
-
-
- -
-
- -
-
-
-
-
-

Looping over a range of numbers

-
-
-
-
-
-
-
-

Don't do this.

- -
-
-
-
-
-
In [6]:
-
-
-
i = 0
-while i < 6:
-    print(i)
-    i += 1
-
- -
-
-
- -
-
- - -
- -
- - -
-
0
-1
-2
-3
-4
-5
-
-
-
- -
-
- -
-
-
-
-
-

Don't do this either.

- -
-
-
-
-
-
In [7]:
-
-
-
for val in [0, 1, 2, 3, 4, 5]:
-    print(val)
-
- -
-
-
- -
-
- - -
- -
- - -
-
0
-1
-2
-3
-4
-5
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [8]:
-
-
-
for val in range(6):
-    print(val)
-
- -
-
-
- -
-
- - -
- -
- - -
-
0
-1
-2
-3
-4
-5
-
-
-
- -
-
- -
-
-
-
-
-

Reversed looping

-
-
-
-
-
-
In [9]:
-
-
-
data = ['first', 'to', 'last', 'from'] 
-
- -
-
-
- -
-
-
-
-
-

This is no good.

- -
-
-
-
-
-
In [10]:
-
-
-
i = len(data) - 1
-while i >= 0:
-    print(data[i])
-    i -= 1
-
- -
-
-
- -
-
- - -
- -
- - -
-
from
-last
-to
-first
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [11]:
-
-
-
for item in reversed(data):
-    print(item)
-
- -
-
-
- -
-
- - -
- -
- - -
-
from
-last
-to
-first
-
-
-
- -
-
- -
-
-
-
-
-

Looping over n collections simultaneously

-
-
-
-
-
-
In [12]:
-
-
-
collection1 = ['a', 'b', 'c']
-collection2 = (10, 20, 30, 40, 50)
-collection3 = ['John', 'Doe', True]
-
- -
-
-
- -
-
-
-
-
-

Oh boy, not like this.

- -
-
-
-
-
-
In [13]:
-
-
-
shortest = len(collection1)
-if len(collection2) < shortest:
-    shortest = len(collection2)
-if len(collection3) < shortest:
-    shortest = len(collection3)
-    
-i = 0
-while i < shortest:
-    print(collection1[i], collection2[i], collection3[i])
-    i += 1
-
- -
-
-
- -
-
- - -
- -
- - -
-
a 10 John
-b 20 Doe
-c 30 True
-
-
-
- -
-
- -
-
-
-
-
-

This is getting better but there's even a better way!

- -
-
-
-
-
-
In [14]:
-
-
-
shortest = min(len(collection1), len(collection2), len(collection3))
-for i in range(shortest):
-    print(collection1[i], collection2[i], collection3[i])
-
- -
-
-
- -
-
- - -
- -
- - -
-
a 10 John
-b 20 Doe
-c 30 True
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [15]:
-
-
-
for first, second, third in zip(collection1, collection2, collection3):
-    print(first, second, third)
-
- -
-
-
- -
-
- - -
- -
- - -
-
a 10 John
-b 20 Doe
-c 30 True
-
-
-
- -
-
- -
-
-
-
-
-

You can also create a dict out of two collections!

- -
-
-
-
-
-
In [16]:
-
-
-
my_dict = dict(zip(collection1, collection2))
-print(my_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'a': 10, 'b': 20, 'c': 30}
-
-
-
- -
-
- -
-
-
-
-
-

for - else - Checking for a match in a collection

Let's say we want to verify a certain condition is met by at least one element in a collection. Let's consider the following relatively naive example where we want to verify that at least one item is "python" (case insensitive) in data. If not, we'll raise a ValueError.

- -
-
-
-
-
-
In [17]:
-
-
-
data = [1, 2, 3, 'This', 'is', 'just', 'a', 'random', 'Python', 'list']
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this

- -
-
-
-
-
-
In [18]:
-
-
-
found = False
-for val in data:
-    if str(val).lower() == 'python':
-        found = True
-        break
-if not found:
-    raise ValueError("Nope, couldn't find.")
-
- -
-
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [19]:
-
-
-
for val in data:
-    if str(val).lower() == 'python':
-        break
-else:
-    raise ValueError("Nope, couldn't find.")
-
- -
-
-
- -
-
-
- - - - - - diff --git a/notebooks/intermediate/html/idiomatic_misc1.html b/notebooks/intermediate/html/idiomatic_misc1.html deleted file mode 100644 index b537c29..0000000 --- a/notebooks/intermediate/html/idiomatic_misc1.html +++ /dev/null @@ -1,12875 +0,0 @@ - - - -tmp_idiomatic_misc1 - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Idiomatic Python - miscellaneous part 1

-
-
-
-
-
-
-
-

Comprehensions

-
-
-
-
-
-
In [1]:
-
-
-
original_data = (1, 2, 3, 4)
-
- -
-
-
- -
-
-
-
-
-

Don't do this.

- -
-
-
-
-
-
In [2]:
-
-
-
# list
-square_roots_list = []
-for val in original_data:
-    square_root = val**(1/2) 
-    square_roots_list.append(square_root)
-print(square_roots_list)
-
-# set
-square_roots_set = set()
-for val in original_data:
-    square_root = val**(1/2) 
-    square_roots_set.add(square_root)
-print(square_roots_set)
-
-# dict
-square_roots_dict = {}
-for val in original_data:
-    square_root = val**(1/2) 
-    square_roots_dict[val] = square_root
-print(square_roots_dict) 
-
-# dict with a condition
-integer_square_roots_dict = {}
-for val in original_data:
-    square_root = val**(1/2)
-    if square_root.is_integer():
-        integer_square_roots_dict[val] = square_root
-print(integer_square_roots_dict) 
-
- -
-
-
- -
-
- - -
- -
- - -
-
[1.0, 1.4142135623730951, 1.7320508075688772, 2.0]
-{1.0, 2.0, 1.7320508075688772, 1.4142135623730951}
-{1: 1.0, 2: 1.4142135623730951, 3: 1.7320508075688772, 4: 2.0}
-{1: 1.0, 4: 2.0}
-
-
-
- -
-
- -
-
-
-
-
-

Note: in case you're using 2.X version of Python for some reason, the result of 1/2 is 0 instead of 0.5.

- -
-
-
-
-
-
-
-

Use comprehensions!

-
-
-
-
-
-
In [3]:
-
-
-
square_roots_list = [val**(1/2) for val in original_data]
-print(square_roots_list)
-
-square_roots_set = {val**(1/2) for val in original_data}
-print(square_roots_set)
-
-square_roots_dict = {val: val**(1/2) for val in original_data}
-print(square_roots_dict)
-
-integer_square_roots_dict = {
-    val: val**(1/2)
-    for val in original_data if (val**(1/2)).is_integer()
-}
-print(integer_square_roots_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
[1.0, 1.4142135623730951, 1.7320508075688772, 2.0]
-{1.0, 2.0, 1.7320508075688772, 1.4142135623730951}
-{1: 1.0, 2: 1.4142135623730951, 3: 1.7320508075688772, 4: 2.0}
-{1: 1.0, 4: 2.0}
-
-
-
- -
-
- -
-
-
-
-
-

Using in for checking presence of an element in a collection

-
-
-
-
-
-
In [4]:
-
-
-
name = 'John Doe'
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [5]:
-
-
-
if name == 'John' or name == 'Doe' or name == 'John Doe':
-    print('This seems to be our guy')
-
- -
-
-
- -
-
- - -
- -
- - -
-
This seems to be our guy
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [6]:
-
-
-
if name in ('John', 'Doe', 'John Doe'):
-    print('This seems to be our guy')
-
- -
-
-
- -
-
- - -
- -
- - -
-
This seems to be our guy
-
-
-
- -
-
- -
-
-
-
-
-

Chained comparisons

-
-
-
-
-
-
In [7]:
-
-
-
a, b, c, d = 1, 2, 3, 4
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [8]:
-
-
-
if b > a and c > b and d > c:
-    print('from lowest to highest: a, b, c, d')
-
- -
-
-
- -
-
- - -
- -
- - -
-
from lowest to highest: a, b, c, d
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [9]:
-
-
-
if a < b < c < d:
-    print('from lowest to highest: a, b, c, d')
-
- -
-
-
- -
-
- - -
- -
- - -
-
from lowest to highest: a, b, c, d
-
-
-
- -
-
- -
-
-
-
-
-

Falsy/truthy values

-
-
-
-
-
-
In [10]:
-
-
-
# These are falsy
-my_list = []
-my_dict = {}
-my_set = set()
-my_tuple = tuple()
-zero = 0
-false = False
-none = None
-my_str = ''
-
-# Basically the rest are truthy
-# for example:
-my_second_list = ['foo']
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [11]:
-
-
-
if len(my_list) == 0:
-    print('Empty list is so empty')
-    
-if not len(my_dict):
-    print('Empty dict is also very empty')
-    
-if not len(my_set) and not len(my_tuple):
-    print('Same goes for sets and tuples')
-    
-if not bool(zero) and not bool(false) and not bool(none) and len(my_str) == 0:
-    print('These are also falsy')
-    
-if len(my_second_list) > 0:
-    print('This should be true')
-
- -
-
-
- -
-
- - -
- -
- - -
-
Empty list is so empty
-Empty dict is also very empty
-Same goes for sets and tuples
-These are also falsy
-This should be true
-
-
-
- -
-
- -
-
-
-
-
-

This is much better!

-
-
-
-
-
-
In [12]:
-
-
-
if not my_list:
-    print('Empty list is so empty')
-    
-if not my_dict:
-    print('Empty dict is also very empty')
-    
-if not my_set and not my_tuple:
-    print('Same goes for sets and tuples')
-    
-if not zero and not false and not none and not my_str:
-    print('These are also falsy')
-    
-if my_second_list:
-    print('This should be true')
-
- -
-
-
- -
-
- - -
- -
- - -
-
Empty list is so empty
-Empty dict is also very empty
-Same goes for sets and tuples
-These are also falsy
-This should be true
-
-
-
- -
-
- -
-
-
-
-
-

any & all

-
-
-
-
-
-
In [13]:
-
-
-
example_collection = ['a', True, 'Python is cool', 123, 0]
-
- -
-
-
- -
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [14]:
-
-
-
any_value_truthy = True
-for val in example_collection:
-    if val:
-        any_value_truthy = True
-        break
-
-all_values_truthy = True
-for val in example_collection:
-    if not val:
-        all_values_truthy = False
-        break
-        
-print('any truthy: {}, all truthy: {}'.format(any_value_truthy, all_values_truthy))
-
- -
-
-
- -
-
- - -
- -
- - -
-
any truthy: True, all truthy: False
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [15]:
-
-
-
any_value_truthy = any(example_collection)
-all_values_truthy = all(example_collection)
-print('any truthy: {}, all truthy: {}'.format(any_value_truthy, all_values_truthy))
-
- -
-
-
- -
-
- - -
- -
- - -
-
any truthy: True, all truthy: False
-
-
-
- -
-
- -
-
-
-
-
-

Pythonic substitute for ternary operator

Many other programming languages have a ternary operator: ?. A common use case for the ternary operator is to assign a certain value to a variable based on some condition. In other words, it could be used like this:

- -
variable = some_condition ? some_value : some_other_value
- -
-
-
-
-
-
-
-

Instead of doing this.

- -
-
-
-
-
-
In [16]:
-
-
-
some_condition = True  # just a dummy condition
-
-if some_condition:
-    variable = 'John'
-else:
-    variable = 'Doe'
-print(variable)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John
-
-
-
- -
-
- -
-
-
-
-
-

You can do it like this!

-
-
-
-
-
-
In [17]:
-
-
-
variable = 'John' if some_condition else 'Doe'
-print(variable)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John
-
-
-
- -
-
- -
-
-
-
-
-

Function keywords arguments

For better readability and maintainability.

- -
-
-
-
-
-
In [18]:
-
-
-
def show_person_details(name, is_gangster, is_hacker, age):
-    print('name: {}, gangster: {}, hacker: {}, age: {}'.format(
-        name, is_gangster, is_hacker, age))
-
- -
-
-
- -
-
-
-
-
-

This is not good. It's hard to tell what `True`, `False` and `83` refer here if you are not familiar with the signature of the `show_person_details` function.

- -
-
-
-
-
-
In [19]:
-
-
-
show_person_details('John Doe', True, False, 83)
-
- -
-
-
- -
-
- - -
- -
- - -
-
name: John Doe, gangster: True, hacker: False, age: 83
-
-
-
- -
-
- -
-
-
-
-
-

This is much better!

-
-
-
-
-
-
In [20]:
-
-
-
show_person_details('John Doe', is_gangster=True, is_hacker=False, age=83)
-
- -
-
-
- -
-
- - -
- -
- - -
-
name: John Doe, gangster: True, hacker: False, age: 83
-
-
-
- -
-
- -
-
-
-
-
-

Extra: keyword only arguments after `*`

This might be useful for example if the signature of the function is likely to change in the future. For example, if there's even a slight chance that one of the arguments may be dropped during the future development, consider using *.

- -
-
-
-
-
-
In [21]:
-
-
-
def func_with_loads_of_args(arg1, *, arg2=None, arg3=None, arg4=None, arg5='boom'):
-    pass
-
-# This won't work because only keyword arguments allowed after *
-#func_with_loads_of_args('John Doe', 1, 2)
-
-# This is ok
-func_with_loads_of_args('John Doe', arg4='foo', arg5='bar', arg2='foo bar')
-
- -
-
-
- -
-
-
-
-
-

Multiple assigment

Let's say we want to swap the values of two variables.

- -
-
-
-
-
-
-
-

Don't do it like this.

- -
-
-
-
-
-
In [22]:
-
-
-
# original values
-a = 1
-b = 2
-
-# swap
-tmp = a
-a = b
-b = tmp
-print(a, b)
-
- -
-
-
- -
-
- - -
- -
- - -
-
2 1
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this!

-
-
-
-
-
-
In [23]:
-
-
-
# original values
-a = 1
-b = 2
-
-# swap
-a, b = b, a
-print(a, b)
-
- -
-
-
- -
-
- - -
- -
- - -
-
2 1
-
-
-
- -
-
- -
-
-
-
-
-

(Un)packing

-
-
-
-
-
-
In [24]:
-
-
-
my_list = [1, 2, 3, 4, 5, 6]
-
- -
-
-
- -
-
-
-
-
-

Don't do something like this.

- -
-
-
-
-
-
In [25]:
-
-
-
first = my_list[0]
-last = my_list[-1]
-middle = my_list[1:-1]
-print(first, middle, last)
-
-packed = [first] + middle + [last]
-assert packed == my_list
-
- -
-
-
- -
-
- - -
- -
- - -
-
1 [2, 3, 4, 5] 6
-
-
-
- -
-
- -
-
-
-
-
-

This is the Pythonic way!

-
-
-
-
-
-
In [26]:
-
-
-
# unpacking
-first, *middle, last = my_list
-print(first, middle, last)
-
-# packing
-packed = [first, *middle, last]
-assert packed == my_list
-
- -
-
-
- -
-
- - -
- -
- - -
-
1 [2, 3, 4, 5] 6
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/intermediate/html/idiomatic_misc2.html b/notebooks/intermediate/html/idiomatic_misc2.html deleted file mode 100644 index ac6087b..0000000 --- a/notebooks/intermediate/html/idiomatic_misc2.html +++ /dev/null @@ -1,12761 +0,0 @@ - - - -tmp_idiomatic_misc2 - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Idiomatic Python - miscellaneous part 2

-
-
-
-
-
-
-
-

String concatenation

-
-
-
-
-
-
In [1]:
-
-
-
names = ('John', 'Lisa', 'Terminator', 'Python')
-
- -
-
-
- -
-
-
-
-
-

Don't do this.

- -
-
-
-
-
-
In [2]:
-
-
-
semicolon_separated = names[0]
-for name in names[1:]:
-    semicolon_separated += ';' + name
-print(semicolon_separated)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John;Lisa;Terminator;Python
-
-
-
- -
-
- -
-
-
-
-
-

Use `join` instead!

-
-
-
-
-
-
In [3]:
-
-
-
semicolon_separated = ';'.join(names)
-print(semicolon_separated)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John;Lisa;Terminator;Python
-
-
-
- -
-
- -
-
-
-
-
-

or in assignments

The return value of a or b:

-
    -
  • a if a is truthy
  • -
  • b otherwise
  • -
-

You can take advantage of this e.g. while writing variable assignments.

- -
-
-
-
-
-
In [4]:
-
-
-
a = 0
-b = None
-c = 'John Doe'
-
- -
-
-
- -
-
-
-
-
-

Instead of doing something like this:

- -
-
-
-
-
-
In [5]:
-
-
-
my_variable = 'default value'
-if a:
-    my_variable = a
-elif b:
-    my_variable = b
-elif c:
-    my_variable = c
-print(my_variable)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John Doe
-
-
-
- -
-
- -
-
-
-
-
-

Prefer doing this:

-
-
-
-
-
-
In [6]:
-
-
-
my_variable = a or b or c or 'default value'
-print(my_variable)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John Doe
-
-
-
- -
-
- -
-
-
-
-
-

try - except - else

-
-
-
-
-
-
-
-

Don't use the following technique for checking if there was exceptions during execution of some block of code.

- -
-
-
-
-
-
In [7]:
-
-
-
exception_occured = False
-try:
-    # here would be the logic of your master piece
-    
-    bad_calculation = 1 / 0
-    
-except ValueError as e:
-    print('Oh boi, some value error: {}'.format(e))
-    exception_occured = True
-except Exception as e:
-    print('Oh boi, something bad happened: {}'.format(e))
-    exception_occured = True
-    
-if not exception_occured:
-    print('All went well!')
-
- -
-
-
- -
-
- - -
- -
- - -
-
Oh boi, something bad happened: division by zero
-
-
-
- -
-
- -
-
-
-
-
-

Use this instead!

-
-
-
-
-
-
In [8]:
-
-
-
try:
-    # here would be the logic of your master piece
-    
-    bad_calculation = 1 / 0
-    
-except ValueError as e:
-    print('Oh boi, some keyerror: {}'.format(e))
-except Exception as e:
-    print('Oh boi, something bad happened: {}'.format(e))
-else:
-    print('All went well!')
-
- -
-
-
- -
-
- - -
- -
- - -
-
Oh boi, something bad happened: division by zero
-
-
-
- -
-
- -
-
-
-
-
-

try - finally

For scenarios where you want to do something always, even when there are exceptions.

- -
-
-
-
-
-
-
-

Don't do it like this

- -
-
-
-
-
-
In [9]:
-
-
-
def magical_calculation():
-    try:
-        # here would be the logic of your master piece
-        result = 1 / 0
-    except ZeroDivisionError:
-        print('This could be something important that should be done every time')
-        return 0
-    except Exception:
-        print('This could be something important that should be done every time')
-        return None
-
-    print('This could be something important that should be done every time')
-    return result
-
-print('return value: {}'.format(magical_calculation()))
-
- -
-
-
- -
-
- - -
- -
- - -
-
This could be something important that should be done every time
-return value: 0
-
-
-
- -
-
- -
-
-
-
-
-

This is better fit for the purpose!

-
-
-
-
-
-
In [10]:
-
-
-
def magical_calculation():
-    try:
-        # here would be the logic of your master piece
-        result = 1 / 0
-    except ZeroDivisionError:
-        return 0
-    except Exception:
-        return None
-    finally:
-        print('This could be something important that should be done every time')
-    return result
-
-print('return value: {}'.format(magical_calculation()))
-
- -
-
-
- -
-
- - -
- -
- - -
-
This could be something important that should be done every time
-return value: 0
-
-
-
- -
-
- -
-
-
-
-
-

Note: You can also have try-except-else-finally structure. In cases where exception is not raised inside try, else will be executed before finally. If there is an expection, else block is not executed.

- -
-
-
-
-
-
-
-

Use context managers when possible

One use case example is file I/O.

- -
-
-
-
-
-
-
-

Don't play with files like this.

- -
-
-
-
-
-
In [11]:
-
-
-
try:
-    some_file = open('tmp.txt', 'w')
-    print('the file is now open: {}'.format(not some_file.closed))
-    
-    # here would be some logic
- 
-finally:
-    some_file.close()
-    print("now it's closed: {}".format(some_file.closed))
-
- -
-
-
- -
-
- - -
- -
- - -
-
the file is now open: True
-now it's closed: True
-
-
-
- -
-
- -
-
-
-
-
-

Use context manager instead!

-
-
-
-
-
-
In [12]:
-
-
-
with open('tmp.txt', 'w') as some_file:
-    print('the file is now open: {}'.format(not some_file.closed))
-    
-    # here would be some logic
-
-print("now it's closed: {}".format(some_file.closed))
-
- -
-
-
- -
-
- - -
- -
- - -
-
the file is now open: True
-now it's closed: True
-
-
-
- -
-
- -
-
-
-
-
-

It's also easy to implement one yourself.

-
-
-
-
-
-
In [13]:
-
-
-
from contextlib import contextmanager
-
-@contextmanager
-def my_context():
-    print('Entering to my context')
-    yield
-    print('Exiting my context')
-    
-def do_stuff():
-    with my_context():
-        print('Doing stuff')
-        
-    print('Doing some stuff outside my context')
-        
-do_stuff()  
-
- -
-
-
- -
-
- - -
- -
- - -
-
Entering to my context
-Doing stuff
-Exiting my context
-Doing some stuff outside my context
-
-
-
- -
-
- -
-
-
-
-
-

min() & max()

-
-
-
-
-
-
In [14]:
-
-
-
secret_data = (1, 2, 5, 99, 8, -9)
-
- -
-
-
- -
-
-
-
-
-

No need to bake it yourself.

- -
-
-
-
-
-
In [15]:
-
-
-
max_value = 0
-for val in secret_data:
-    if val > max_value:
-        max_value = val
-print(max_value)
-
- -
-
-
- -
-
- - -
- -
- - -
-
99
-
-
-
- -
-
- -
-
-
-
-
-

Use builtin functionality instead!

-
-
-
-
-
-
In [16]:
-
-
-
max_value = max(secret_data)
-print(max_value)
-
- -
-
-
- -
-
- - -
- -
- - -
-
99
-
-
-
- -
-
- -
-
-
-
-
-

contextlib.suppress - ignoring exceptions

-
-
-
-
-
-
-
-

If there's a potential exception that is ok, don't handle it like this.

- -
-
-
-
-
-
In [17]:
-
-
-
value = 0
-try:
-    value = 1 / 0  # just for demonstrating purposes 
-except ZeroDivisionError:
-    pass
-
-print(value)
-
- -
-
-
- -
-
- - -
- -
- - -
-
0
-
-
-
- -
-
- -
-
-
-
-
-

Do it like this instead!

-
-
-
-
-
-
In [18]:
-
-
-
from contextlib import suppress
-
-value = 0
-with suppress(ZeroDivisionError):
-    value = 1 / 0  # just for demonstrating purposes
-    
-print(value)
-
- -
-
-
- -
-
- - -
- -
- - -
-
0
-
-
-
- -
-
- -
-
-
-
-
-

Properties instead of getter/setter methods

-
-
-
-
-
-
-
-

Instead of doing something like this.

- -
-
-
-
-
-
In [19]:
-
-
-
class Person:
-    def __init__(self, first_name, last_name):
-        self.first_name = first_name
-        self.last_name = last_name
-        
-    def get_full_name(self):
-        return '{} {}'.format(self.first_name, self.last_name)
-    
-    def set_full_name(self, full_name):
-        parts = full_name.split()
-        if len(parts) != 2:
-            raise ValueError('Sorry, too difficult name')
-            
-        self.first_name, self.last_name = parts 
-        
-      
-p = Person('John', 'Doe')
-print(p.get_full_name())
-p.set_full_name('Lisa Doe')
-print(p.get_full_name())
-
- -
-
-
- -
-
- - -
- -
- - -
-
John Doe
-Lisa Doe
-
-
-
- -
-
- -
-
-
-
-
-

Prefer properties!

-
-
-
-
-
-
In [20]:
-
-
-
class Person:
-    def __init__(self, first_name, last_name):
-        self.first_name = first_name
-        self.last_name = last_name
-        
-    @property
-    def full_name(self):
-        return '{} {}'.format(self.first_name, self.last_name)
-    
-    @full_name.setter
-    def full_name(self, name):
-        parts = name.split()
-        if len(parts) != 2:
-            raise ValueError('Sorry, too difficult name')
-            
-        self.first_name, self.last_name = parts
-
-    
-p = Person('John', 'Doe')
-print(p.full_name)
-p.full_name = 'Lisa Doe'
-print(p.full_name)
-
- -
-
-
- -
-
- - -
- -
- - -
-
John Doe
-Lisa Doe
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/intermediate/html/pytest_fixtures.html b/notebooks/intermediate/html/pytest_fixtures.html deleted file mode 100644 index 665ffc7..0000000 --- a/notebooks/intermediate/html/pytest_fixtures.html +++ /dev/null @@ -1,12542 +0,0 @@ - - - -tmp_pytest_fixtures - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Efficient use of pytest fixtures

-
-
-
-
-
-
-
-

Required boilerplate for using pytest inside notebooks.

- -
-
-
-
-
-
In [1]:
-
-
-
# Let's make sure pytest and ipytest packages are installed
-# ipytest is required for running pytest inside Jupyter notebooks
-import sys
-!{sys.executable} -m pip install pytest 'ipytest>=0.3.0'
-
-import pytest
-from ipytest import magics, clean_tests
-__file__ = 'pytest_fixtures.ipynb'
-
- -
-
-
- -
-
- - -
- -
- - -
-
Requirement already satisfied: pytest in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (3.5.0)
-Requirement already satisfied: ipytest>=0.3.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (0.3.0)
-Requirement already satisfied: attrs>=17.4.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (17.4.0)
-Requirement already satisfied: pluggy<0.7,>=0.5 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (0.6.0)
-Requirement already satisfied: setuptools in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (39.0.1)
-Requirement already satisfied: py>=1.5.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (1.5.3)
-Requirement already satisfied: more-itertools>=4.0.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (4.1.0)
-Requirement already satisfied: six>=1.10.0 in /Users/jerry/.virtualenvs/learn-python3/lib/python3.5/site-packages (from pytest) (1.11.0)
-
-
-
- -
-
- -
-
-
-
-
-

Parametrizing fixtures

Similarly as you can parametrize test functions with pytest.mark.parametrize, you can parametrize fixtures:

- -
-
-
-
-
-
In [2]:
-
-
-
PATHS = ['/foo/bar.txt', '/bar/baz.txt']
-
-@pytest.fixture(params=PATHS)
-def executable(request):
-    return request.param
-
- -
-
-
- -
-
-
-
In [3]:
-
-
-
%%run_pytest[clean] '-s'
-
-def test_something_with_executable(executable):
-    print(executable)
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 2 items
-
-pytest_fixtures.py /foo/bar.txt
-./bar/baz.txt
-.
-
-============================================================================== 2 passed in 0.02 seconds ==============================================================================
-
-
-
- -
-
- -
-
-
-
-
-

pytest.mark.usefixtures

pytest.mark.usefixtures is useful especially when you want to use some fixture in a set of tests but you don't need the return value of the fixture.

- -
-
-
-
-
-
In [4]:
-
-
-
@pytest.fixture
-def my_fixture():
-    print('\nmy_fixture is used')
-
-@pytest.fixture
-def other_fixture():
-    return 'FOO'
-
- -
-
-
- -
-
-
-
In [5]:
-
-
-
%%run_pytest[clean] '-s'
-
-@pytest.mark.usefixtures('my_fixture')
-class TestMyStuff:
-    def test_somestuff(self):
-        pass
-    
-    def test_some_other_stuff(self, other_fixture):
-        print('here we use also other_fixture which returns: {}'.format(other_fixture))
-        pass
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 2 items
-
-pytest_fixtures.py 
-my_fixture is used
-.
-my_fixture is used
-here we use also other_fixture which returns: FOO
-.
-
-================================================================================== warnings summary ==================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================== 2 passed, 1 warnings in 0.02 seconds ========================================================================
-
-
-
- -
-
- -
-
-
-
In [6]:
-
-
-
# Needed to clean up test classes (Test*) in ipytest
-clean_tests('Test*')
-
- -
-
-
- -
-
-
-
-
-

pytest built-in fixtures

Here are a couple of examples of the useful built-in fixtures, you can view all available fixtures by running pytest --fixtures.

- -
-
-
-
-
-
-
-

monkeypatch

Built-in monkeypatch fixture lets you e.g. set environment variables and set/delete attributes of objects. The use cases are similar as with patching/mocking with unittest.mock.patch/unittest.mock.MagicMock which are part of the Python Standard Library.

-

Monkeypatching environment variables:

- -
-
-
-
-
-
In [7]:
-
-
-
import os
-
-def get_env_var_or_none(var_name):
-    return os.environ.get(var_name, None)
-
- -
-
-
- -
-
-
-
In [8]:
-
-
-
%%run_pytest[clean] '-s'
-
-def test_get_env_var_or_none_with_valid_env_var(monkeypatch):
-    monkeypatch.setenv('MY_ENV_VAR', 'secret')
-    res = get_env_var_or_none('MY_ENV_VAR')
-    assert res == 'secret'
-    
-def test_get_env_var_or_none_with_missing_env_var():
-    res = get_env_var_or_none('NOT_EXISTING')
-    assert res is None
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 2 items
-
-pytest_fixtures.py ..
-
-================================================================================== warnings summary ==================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================== 2 passed, 1 warnings in 0.02 seconds ========================================================================
-
-
-
- -
-
- -
-
-
-
-
-

Monkeypatching attributes:

- -
-
-
-
-
-
In [9]:
-
-
-
class SomeClass:
-    some_value = 'some value'
-    
-    @staticmethod
-    def tell_the_truth():
-        print('This is the original truth')
-
- -
-
-
- -
-
-
-
In [10]:
-
-
-
def fake_truth():
-    print('This is modified truth')
-
-@pytest.fixture
-def fake_some_class(monkeypatch): 
-    monkeypatch.setattr('__main__.SomeClass.some_value', 'fake value')
-    monkeypatch.setattr('__main__.SomeClass.tell_the_truth', fake_truth)
-
- -
-
-
- -
-
-
-
In [11]:
-
-
-
%%run_pytest[clean] '-s'
-
-def test_some_class(fake_some_class):
-    print(SomeClass.some_value)
-    SomeClass.tell_the_truth()
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 1 item
-
-pytest_fixtures.py fake value
-This is modified truth
-.
-
-================================================================================== warnings summary ==================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================== 1 passed, 1 warnings in 0.02 seconds ========================================================================
-
-
-
- -
-
- -
-
-
-
-
-

tmpdir

tmpdir fixture provides functionality for creating temporary files and directories.

- -
-
-
-
-
-
In [12]:
-
-
-
def word_count_of_txt_file(file_path):
-    with open(file_path, 'r') as f:
-        content = f.read()
-        return len(content.split())
-
- -
-
-
- -
-
-
-
In [13]:
-
-
-
%%run_pytest[clean] '-s'
-
-def test_word_count(tmpdir):
-    test_file = tmpdir.join('test.txt')
-    test_file.write('This is example content of seven words')
-    res = word_count_of_txt_file(str(test_file)) # str returns the path
-    assert res == 7
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 1 item
-
-pytest_fixtures.py .
-
-================================================================================== warnings summary ==================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================== 1 passed, 1 warnings in 0.02 seconds ========================================================================
-
-
-
- -
-
- -
-
-
-
-
-

Fixture scope

-
-
-
-
-
-
In [14]:
-
-
-
# scope is function also by default
-@pytest.fixture(scope='function')
-def func_fixture():
-    print('\nfunc')
-    
-@pytest.fixture(scope='module')
-def module_fixture():
-    print('\nmodule')
-    
-@pytest.fixture(scope='session')
-def session_fixture():
-    print('\nsession')  
-
- -
-
-
- -
-
-
-
In [15]:
-
-
-
%%run_pytest[clean] '-s'
-
-def test_something(func_fixture, module_fixture, session_fixture):
-    pass
-
-def test_something_else(func_fixture, module_fixture, session_fixture):
-    pass
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 2 items
-
-pytest_fixtures.py 
-session
-
-module
-
-func
-.
-func
-.
-
-================================================================================== warnings summary ==================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================== 2 passed, 1 warnings in 0.02 seconds ========================================================================
-
-
-
- -
-
- -
-
-
-
-
-

Setup-teardown behaviour

-
-
-
-
-
-
In [16]:
-
-
-
@pytest.fixture
-def some_fixture():
-    print('some_fixture is run now')
-    yield 'some magical value'
-    print('\nthis will be run after test execution, you can do e.g. some clean up here')
-
- -
-
-
- -
-
-
-
In [17]:
-
-
-
%%run_pytest[clean] '-s'
-
-def test_something(some_fixture):
-    print('running test_something')
-    assert some_fixture == 'some magical value'
-    print('test ends here')
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 1 item
-
-pytest_fixtures.py some_fixture is run now
-running test_something
-test ends here
-.
-this will be run after test execution, you can do e.g. some clean up here
-
-
-================================================================================== warnings summary ==================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================== 1 passed, 1 warnings in 0.02 seconds ========================================================================
-
-
-
- -
-
- -
-
-
-
-
-

Using fixtures automatically

-
-
-
-
-
-
In [18]:
-
-
-
@pytest.fixture(autouse=True)
-def my_fixture():
-    print('\nusing my_fixture')
-
- -
-
-
- -
-
-
-
In [19]:
-
-
-
%%run_pytest[clean] '-s'
-
-def test_1():
-    pass
-    
-def test_2():
-    pass
-
- -
-
-
- -
-
- - -
- -
- - -
-
================================================================================ test session starts =================================================================================
-platform darwin -- Python 3.5.4, pytest-3.5.0, py-1.5.3, pluggy-0.6.0
-rootdir: /Users/jerry/github/jerry-git/learn-python3, inifile: pytest.ini
-plugins: nbval-0.9.0
-collected 2 items
-
-pytest_fixtures.py 
-using my_fixture
-.
-using my_fixture
-.
-
-================================================================================== warnings summary ==================================================================================
-None
-  Module already imported so cannot be rewritten: nbval
-
--- Docs: http://doc.pytest.org/en/latest/warnings.html
-======================================================================== 2 passed, 1 warnings in 0.02 seconds ========================================================================
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/intermediate/html/std_lib2.html b/notebooks/intermediate/html/std_lib2.html deleted file mode 100644 index a0a8d32..0000000 --- a/notebooks/intermediate/html/std_lib2.html +++ /dev/null @@ -1,12366 +0,0 @@ - - - -tmp_std_lib2 - - - - - - - - - - - - - - - - - - - -
-
- - -
- - -
-
-
-
-
-

Goodies of the Python Standard Library

-
-
-
-
-
-
-
-

json for encoding and decoding JSON

Because the web is filled with JSON nowadays and the good days of xml are gone.

- -
-
-
-
-
-
In [1]:
-
-
-
data = {'b': True, 'a': 1, 'nested': {'foo': 'bar'}, 'c': None, 'some_list': [1, 2, 3]}
-
- -
-
-
- -
-
-
-
-
-

Encoding

-
-
-
-
-
-
In [2]:
-
-
-
import json
-json_data = json.dumps(data)
-print('type: {} data: {}'.format(type(json_data), json_data))
-
- -
-
-
- -
-
- - -
- -
- - -
-
type: <class 'str'> data: {"c": null, "b": true, "some_list": [1, 2, 3], "a": 1, "nested": {"foo": "bar"}}
-
-
-
- -
-
- -
-
-
-
-
-

Decoding

-
-
-
-
-
-
In [3]:
-
-
-
decoded = json.loads(json_data)
-print('type: {} data: {}'.format(type(decoded), decoded))
-
- -
-
-
- -
-
- - -
- -
- - -
-
type: <class 'dict'> data: {'c': None, 'nested': {'foo': 'bar'}, 'b': True, 'some_list': [1, 2, 3], 'a': 1}
-
-
-
- -
-
- -
-
-
-
-
-

unittest.mock

Although pytest is the preferred testing framework, unittest.mock module offers some goodies that are helpful also in pytest test cases. Mocking and patching are generally useful for "faking" some parts of the logic/state of the software under test. Common use cases are, for example, patching parts of code that interact with 3rd parties (e.g. some web services).

- -
-
-
-
-
-
-
-

MagicMock

In general, Mocks are simulated objects that replace the functionality/state of a real world object in a controlled way. Thus, they are especially useful in tests for mimicing some behavior of a specific part of the implementation under test.

-

There is also a Mock class in the Python Standard Library but you usually want to use MagicMock which is a subclass of Mock. MagicMock provides default implementation for the most of the magic methods (e.g. __setitem__() and __getitem__())

-

A potential use case could be something like this:

- -
-
-
-
-
-
In [4]:
-
-
-
import random
-
-class Client:
-    def __init__(self, url, username, password):
-        self.url = url
-        self.creds = (username, password)
-        
-    def fetch_some_data(self):
-        print('Here we could for example fetch data from 3rd party API and return the data.')
-        print('Now we will just return some random number between 1-100.')
-        return random.randint(1, 100)
-
-
-class MyApplication:
-    def __init__(self):
-        self.client = Client(url='https://somewhere/api', username='John Doe', password='secret123?')
-        
-    def do_something_fancy(self):
-        data = self.client.fetch_some_data()
-        return data**(1/2) # let's return a square root just for example
-    
-    
-####################
-# In the test module:
-
-from unittest.mock import MagicMock
-
-# Inside a test case:
-app = MyApplication()
-app.client = MagicMock() # Mock the client
-app.client.fetch_some_data.return_value = 4  # Set controlled behaviour
-result = app.do_something_fancy()
-assert result == 2
-print('All good, woop woop!')
-
- -
-
-
- -
-
- - -
- -
- - -
-
All good, woop woop!
-
-
-
- -
-
- -
-
-
-
-
-

patch

The use cases of patch are pretty similar to MacigMock. The biggest difference is that patch is used as a context manager or a decorator. Object to be patched is given as an argument for patch. In addition, you can provide additional object as a second argument (new) which will replace the original one. In case the new is omitted, MagicMock will be used by default.

-

Let's see how the example above would look like with patch.

- -
-
-
-
-
-
In [5]:
-
-
-
# In the test module:
-
-from unittest.mock import patch
-
-# Inside a test case:
-app = MyApplication()
-with patch('__main__.app.client') as patched_client:  # Patch the client 
-    patched_client.fetch_some_data.return_value = 4 # Set controlled behaviour
-    result = app.do_something_fancy()
-    assert result == 2
-    print('All good, woop woop!')
-
- -
-
-
- -
-
- - -
- -
- - -
-
All good, woop woop!
-
-
-
- -
-
- -
-
-
-
-
-

The same but with a function decorator instead of a context manager. Note that here we are patching the whole Client class, not just the client instance variable of app.

- -
-
-
-
-
-
In [6]:
-
-
-
from unittest.mock import patch
-
-@patch('__main__.Client') # Patch the Client
-def test_do_something_fancy(client_cls):
-    client_cls().fetch_some_data.return_value = 4 # Set controlled behaviour
-    app = MyApplication()
-    result = app.do_something_fancy()
-    assert result == 2
-    print('All good, woop woop!')
-    
-    
-test_do_something_fancy()  # This is just for the sake of example
-
- -
-
-
- -
-
- - -
- -
- - -
-
All good, woop woop!
-
-
-
- -
-
- -
-
-
- -
-
-
-
-
-

namedtuple

A great helper for creating more readable and self documenting code.

-

namedtuple is a function that returns a tuple whose fields have names and also the tuple itself has a name (just like classes and their instance variables). Potential use cases include storing data which should be immutable. If you can use Python 3.7 or newer, you may want to take a look at dataclasses as well.

- -
-
-
-
-
-
In [7]:
-
-
-
from collections import namedtuple
-
-Person = namedtuple('Person', ['name', 'age', 'is_gangster'])
-
-# instance creation is similar to classes
-john = Person('John Doe', 83, True)
-lisa = Person('Lis Doe', age=77, is_gangster=False)
-
-print(john, lisa)
-print('Is John a gangster: {}'.format(john.is_gangster))
-
-# tuples are immutable, thus you can't do this
-#john.is_gangster = False
-
- -
-
-
- -
-
- - -
- -
- - -
-
Person(name='John Doe', age=83, is_gangster=True) Person(name='Lis Doe', age=77, is_gangster=False)
-Is John a gangster: True
-
-
-
- -
-
- -
-
-
-
-
-

Counter

For counting the occurences of elements in a collection.

- -
-
-
-
-
-
In [8]:
-
-
-
from collections import Counter
-
-data = [1, 2, 3, 1, 2, 4, 5, 6, 2]
-
-counter = Counter(data)
-print('type: {}, counter: {}'.format(type(counter), counter))
-
-print('count of twos: {}'.format(counter[2]))
-print('count of tens: {}'.format(counter[10])) # zero for non existing
-
-print('counter is a dict: {}'.format(isinstance(counter, dict)))
-
- -
-
-
- -
-
- - -
- -
- - -
-
type: <class 'collections.Counter'>, counter: Counter({2: 3, 1: 2, 3: 1, 4: 1, 5: 1, 6: 1})
-count of twos: 3
-count of tens: 0
-counter is a dict: True
-
-
-
- -
-
- -
-
-
-
-
-

defaultdict

For cleaner code for populating dictionaries.

-

Let's first see how you could use a normal dict.

- -
-
-
-
-
-
In [9]:
-
-
-
data = (1, 2, 3, 4, 3, 2, 5, 6, 7)
-
-my_dict = {}
-for val in data:
-    if val % 2:
-        if not 'odd' in my_dict:
-            my_dict['odd'] = []
-        my_dict['odd'].append(val)
-    else:
-        if not 'even' in my_dict:
-            my_dict['even'] = []
-        my_dict['even'].append(val)
-        
-print(my_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
{'even': [2, 4, 2, 6], 'odd': [1, 3, 3, 5, 7]}
-
-
-
- -
-
- -
-
-
-
-
-

With defaultdict:

- -
-
-
-
-
-
In [10]:
-
-
-
from collections import defaultdict
-
-my_dict = defaultdict(list)
-for val in data:
-    if val % 2:
-        my_dict['odd'].append(val)
-    else:
-        my_dict['even'].append(val)
-print(my_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
defaultdict(<class 'list'>, {'even': [2, 4, 2, 6], 'odd': [1, 3, 3, 5, 7]})
-
-
-
- -
-
- -
-
-
-
-
-

In the above example, defaultdict makes sure that a fresh list is automatically initialized as a value when a new key is added.

-

Here's another example with int as a default.

- -
-
-
-
-
-
In [11]:
-
-
-
my_dict = defaultdict(int)
-for val in data:
-    if val % 2:
-        my_dict['odd_count'] += 1
-    else:
-        my_dict['even_count'] += 1
-print(my_dict)
-
- -
-
-
- -
-
- - -
- -
- - -
-
defaultdict(<class 'int'>, {'even_count': 4, 'odd_count': 5})
-
-
-
- -
-
- -
-
-
- - - - - - diff --git a/notebooks/intermediate/notebooks/best_practices.ipynb b/notebooks/intermediate/notebooks/01_best_practices.ipynb similarity index 100% rename from notebooks/intermediate/notebooks/best_practices.ipynb rename to notebooks/intermediate/notebooks/01_best_practices.ipynb diff --git a/notebooks/intermediate/notebooks/idiomatic_loops.ipynb b/notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb similarity index 94% rename from notebooks/intermediate/notebooks/idiomatic_loops.ipynb rename to notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb index bc52b64..4b3f446 100644 --- a/notebooks/intermediate/notebooks/idiomatic_loops.ipynb +++ b/notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb @@ -20,7 +20,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = ['John', 'Doe', 'was', 'here']" + "data = [\"John\", \"Doe\", \"was\", \"here\"]" ] }, { @@ -90,7 +90,7 @@ "outputs": [], "source": [ "for idx, val in enumerate(data):\n", - " print('{}: {}'.format(idx, val))" + " print(\"{}: {}\".format(idx, val))" ] }, { @@ -166,7 +166,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = ['first', 'to', 'last', 'from'] " + "data = [\"first\", \"to\", \"last\", \"from\"]" ] }, { @@ -218,9 +218,9 @@ "metadata": {}, "outputs": [], "source": [ - "collection1 = ['a', 'b', 'c']\n", + "collection1 = [\"a\", \"b\", \"c\"]\n", "collection2 = (10, 20, 30, 40, 50)\n", - "collection3 = ['John', 'Doe', True]" + "collection3 = [\"John\", \"Doe\", True]" ] }, { @@ -241,11 +241,11 @@ " shortest = len(collection2)\n", "if len(collection3) < shortest:\n", " shortest = len(collection3)\n", - " \n", + "\n", "i = 0\n", "while i < shortest:\n", " print(collection1[i], collection2[i], collection3[i])\n", - " i += 1\n" + " i += 1" ] }, { @@ -314,7 +314,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = [1, 2, 3, 'This', 'is', 'just', 'a', 'random', 'Python', 'list']" + "data = [1, 2, 3, \"This\", \"is\", \"just\", \"a\", \"random\", \"Python\", \"list\"]" ] }, { @@ -332,7 +332,7 @@ "source": [ "found = False\n", "for val in data:\n", - " if str(val).lower() == 'python':\n", + " if str(val).lower() == \"python\":\n", " found = True\n", " break\n", "if not found:\n", @@ -353,7 +353,7 @@ "outputs": [], "source": [ "for val in data:\n", - " if str(val).lower() == 'python':\n", + " if str(val).lower() == \"python\":\n", " break\n", "else:\n", " raise ValueError(\"Nope, couldn't find.\")" diff --git a/notebooks/intermediate/notebooks/pytest_fixtures.ipynb b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb similarity index 82% rename from notebooks/intermediate/notebooks/pytest_fixtures.ipynb rename to notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb index 1182c37..09f5ca0 100644 --- a/notebooks/intermediate/notebooks/pytest_fixtures.ipynb +++ b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb @@ -23,11 +23,16 @@ "# Let's make sure pytest and ipytest packages are installed\n", "# ipytest is required for running pytest inside Jupyter notebooks\n", "import sys\n", - "!{sys.executable} -m pip install pytest 'ipytest>=0.3.0'\n", "\n", - "import pytest\n", - "from ipytest import magics, clean_tests\n", - "__file__ = 'pytest_fixtures.ipynb'" + "!{sys.executable} -m pip install pytest\n", + "!{sys.executable} -m pip install ipytest\n", + "\n", + "# These are needed for running pytest inside Jupyter notebooks\n", + "import ipytest\n", + "\n", + "ipytest.autoconfig()\n", + "\n", + "import pytest" ] }, { @@ -44,7 +49,8 @@ "metadata": {}, "outputs": [], "source": [ - "PATHS = ['/foo/bar.txt', '/bar/baz.txt']\n", + "PATHS = [\"/foo/bar.txt\", \"/bar/baz.txt\"]\n", + "\n", "\n", "@pytest.fixture(params=PATHS)\n", "def executable(request):\n", @@ -57,7 +63,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "def test_something_with_executable(executable):\n", " print(executable)" @@ -79,11 +85,12 @@ "source": [ "@pytest.fixture\n", "def my_fixture():\n", - " print('\\nmy_fixture is used')\n", + " print(\"\\nmy_fixture is used\")\n", + "\n", "\n", "@pytest.fixture\n", "def other_fixture():\n", - " return 'FOO'" + " return \"FOO\"" ] }, { @@ -92,7 +99,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "@pytest.mark.usefixtures('my_fixture')\n", "class TestMyStuff:\n", @@ -104,16 +111,6 @@ " pass" ] }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Needed to clean up test classes (Test*) in ipytest\n", - "clean_tests('Test*')" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -140,6 +137,7 @@ "source": [ "import os\n", "\n", + "\n", "def get_env_var_or_none(var_name):\n", " return os.environ.get(var_name, None)" ] @@ -150,7 +148,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "def test_get_env_var_or_none_with_valid_env_var(monkeypatch):\n", " monkeypatch.setenv('MY_ENV_VAR', 'secret')\n", @@ -176,11 +174,11 @@ "outputs": [], "source": [ "class SomeClass:\n", - " some_value = 'some value'\n", - " \n", + " some_value = \"some value\"\n", + "\n", " @staticmethod\n", " def tell_the_truth():\n", - " print('This is the original truth')" + " print(\"This is the original truth\")" ] }, { @@ -190,12 +188,13 @@ "outputs": [], "source": [ "def fake_truth():\n", - " print('This is modified truth')\n", + " print(\"This is modified truth\")\n", + "\n", "\n", "@pytest.fixture\n", - "def fake_some_class(monkeypatch): \n", - " monkeypatch.setattr('__main__.SomeClass.some_value', 'fake value')\n", - " monkeypatch.setattr('__main__.SomeClass.tell_the_truth', fake_truth)" + "def fake_some_class(monkeypatch):\n", + " monkeypatch.setattr(\"__main__.SomeClass.some_value\", \"fake value\")\n", + " monkeypatch.setattr(\"__main__.SomeClass.tell_the_truth\", fake_truth)" ] }, { @@ -204,7 +203,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "def test_some_class(fake_some_class):\n", " print(SomeClass.some_value)\n", @@ -226,7 +225,7 @@ "outputs": [], "source": [ "def word_count_of_txt_file(file_path):\n", - " with open(file_path, 'r') as f:\n", + " with open(file_path, \"r\") as f:\n", " content = f.read()\n", " return len(content.split())" ] @@ -237,7 +236,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "def test_word_count(tmpdir):\n", " test_file = tmpdir.join('test.txt')\n", @@ -260,17 +259,19 @@ "outputs": [], "source": [ "# scope is function also by default\n", - "@pytest.fixture(scope='function')\n", + "@pytest.fixture(scope=\"function\")\n", "def func_fixture():\n", - " print('\\nfunc')\n", - " \n", - "@pytest.fixture(scope='module')\n", + " print(\"\\nfunc\")\n", + "\n", + "\n", + "@pytest.fixture(scope=\"module\")\n", "def module_fixture():\n", - " print('\\nmodule')\n", - " \n", - "@pytest.fixture(scope='session')\n", + " print(\"\\nmodule\")\n", + "\n", + "\n", + "@pytest.fixture(scope=\"session\")\n", "def session_fixture():\n", - " print('\\nsession') " + " print(\"\\nsession\")" ] }, { @@ -279,7 +280,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "def test_something(func_fixture, module_fixture, session_fixture):\n", " pass\n", @@ -303,9 +304,9 @@ "source": [ "@pytest.fixture\n", "def some_fixture():\n", - " print('some_fixture is run now')\n", - " yield 'some magical value'\n", - " print('\\nthis will be run after test execution, you can do e.g. some clean up here')" + " print(\"some_fixture is run now\")\n", + " yield \"some magical value\"\n", + " print(\"\\nthis will be run after test execution, you can do e.g. some clean up here\")" ] }, { @@ -314,7 +315,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "def test_something(some_fixture):\n", " print('running test_something')\n", @@ -337,7 +338,7 @@ "source": [ "@pytest.fixture(autouse=True)\n", "def my_fixture():\n", - " print('\\nusing my_fixture')" + " print(\"\\nusing my_fixture\")" ] }, { @@ -346,7 +347,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean] '-s'\n", + "%%ipytest -s\n", "\n", "def test_1():\n", " pass\n", @@ -358,7 +359,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -372,7 +373,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.10.3" } }, "nbformat": 4, diff --git a/notebooks/intermediate/notebooks/std_lib2.ipynb b/notebooks/intermediate/notebooks/01_std_lib2.ipynb similarity index 79% rename from notebooks/intermediate/notebooks/std_lib2.ipynb rename to notebooks/intermediate/notebooks/01_std_lib2.ipynb index aac47c7..b567924 100644 --- a/notebooks/intermediate/notebooks/std_lib2.ipynb +++ b/notebooks/intermediate/notebooks/01_std_lib2.ipynb @@ -21,7 +21,7 @@ "metadata": {}, "outputs": [], "source": [ - "data = {'b': True, 'a': 1, 'nested': {'foo': 'bar'}, 'c': None, 'some_list': [1, 2, 3]}" + "data = {\"b\": True, \"a\": 1, \"nested\": {\"foo\": \"bar\"}, \"c\": None, \"some_list\": [1, 2, 3]}" ] }, { @@ -38,8 +38,9 @@ "outputs": [], "source": [ "import json\n", + "\n", "json_data = json.dumps(data)\n", - "print('type: {} data: {}'.format(type(json_data), json_data))" + "print(\"type: {} data: {}\".format(type(json_data), json_data))" ] }, { @@ -56,7 +57,7 @@ "outputs": [], "source": [ "decoded = json.loads(json_data)\n", - "print('type: {} data: {}'.format(type(decoded), decoded))" + "print(\"type: {} data: {}\".format(type(decoded), decoded))" ] }, { @@ -88,26 +89,31 @@ "source": [ "import random\n", "\n", + "\n", "class Client:\n", " def __init__(self, url, username, password):\n", " self.url = url\n", " self.creds = (username, password)\n", - " \n", + "\n", " def fetch_some_data(self):\n", - " print('Here we could for example fetch data from 3rd party API and return the data.')\n", - " print('Now we will just return some random number between 1-100.')\n", + " print(\n", + " \"Here we could for example fetch data from 3rd party API and return the data.\"\n", + " )\n", + " print(\"Now we will just return some random number between 1-100.\")\n", " return random.randint(1, 100)\n", "\n", "\n", "class MyApplication:\n", " def __init__(self):\n", - " self.client = Client(url='https://somewhere/api', username='John Doe', password='secret123?')\n", - " \n", + " self.client = Client(\n", + " url=\"https://somewhere/api/", username=\"John Doe\", password=\"secret123?\"\n", + " )\n", + "\n", " def do_something_fancy(self):\n", " data = self.client.fetch_some_data()\n", - " return data**(1/2) # let's return a square root just for example\n", - " \n", - " \n", + " return data ** (1 / 2) # let's return a square root just for example\n", + "\n", + "\n", "####################\n", "# In the test module:\n", "\n", @@ -115,11 +121,11 @@ "\n", "# Inside a test case:\n", "app = MyApplication()\n", - "app.client = MagicMock() # Mock the client\n", + "app.client = MagicMock() # Mock the client\n", "app.client.fetch_some_data.return_value = 4 # Set controlled behaviour\n", "result = app.do_something_fancy()\n", "assert result == 2\n", - "print('All good, woop woop!')" + "print(\"All good, woop woop!\")" ] }, { @@ -144,11 +150,11 @@ "\n", "# Inside a test case:\n", "app = MyApplication()\n", - "with patch('__main__.app.client') as patched_client: # Patch the client \n", - " patched_client.fetch_some_data.return_value = 4 # Set controlled behaviour\n", + "with patch(\"__main__.app.client\") as patched_client: # Patch the client\n", + " patched_client.fetch_some_data.return_value = 4 # Set controlled behaviour\n", " result = app.do_something_fancy()\n", " assert result == 2\n", - " print('All good, woop woop!')" + " print(\"All good, woop woop!\")" ] }, { @@ -166,15 +172,16 @@ "source": [ "from unittest.mock import patch\n", "\n", - "@patch('__main__.Client') # Patch the Client\n", + "\n", + "@patch(\"__main__.Client\") # Patch the Client\n", "def test_do_something_fancy(client_cls):\n", - " client_cls().fetch_some_data.return_value = 4 # Set controlled behaviour\n", + " client_cls().fetch_some_data.return_value = 4 # Set controlled behaviour\n", " app = MyApplication()\n", " result = app.do_something_fancy()\n", " assert result == 2\n", - " print('All good, woop woop!')\n", - " \n", - " \n", + " print(\"All good, woop woop!\")\n", + "\n", + "\n", "test_do_something_fancy() # This is just for the sake of example" ] }, @@ -203,17 +210,17 @@ "source": [ "from collections import namedtuple\n", "\n", - "Person = namedtuple('Person', ['name', 'age', 'is_gangster'])\n", + "Person = namedtuple(\"Person\", [\"name\", \"age\", \"is_gangster\"])\n", "\n", "# instance creation is similar to classes\n", - "john = Person('John Doe', 83, True)\n", - "lisa = Person('Lis Doe', age=77, is_gangster=False)\n", + "john = Person(\"John Doe\", 83, True)\n", + "lisa = Person(\"Lis Doe\", age=77, is_gangster=False)\n", "\n", "print(john, lisa)\n", - "print('Is John a gangster: {}'.format(john.is_gangster))\n", + "print(\"Is John a gangster: {}\".format(john.is_gangster))\n", "\n", "# tuples are immutable, thus you can't do this\n", - "#john.is_gangster = False" + "# john.is_gangster = False" ] }, { @@ -235,12 +242,12 @@ "data = [1, 2, 3, 1, 2, 4, 5, 6, 2]\n", "\n", "counter = Counter(data)\n", - "print('type: {}, counter: {}'.format(type(counter), counter))\n", + "print(\"type: {}, counter: {}\".format(type(counter), counter))\n", "\n", - "print('count of twos: {}'.format(counter[2]))\n", - "print('count of tens: {}'.format(counter[10])) # zero for non existing\n", + "print(\"count of twos: {}\".format(counter[2]))\n", + "print(\"count of tens: {}\".format(counter[10])) # zero for non existing\n", "\n", - "print('counter is a dict: {}'.format(isinstance(counter, dict)))" + "print(\"counter is a dict: {}\".format(isinstance(counter, dict)))" ] }, { @@ -264,14 +271,14 @@ "my_dict = {}\n", "for val in data:\n", " if val % 2:\n", - " if not 'odd' in my_dict:\n", - " my_dict['odd'] = []\n", - " my_dict['odd'].append(val)\n", + " if not \"odd\" in my_dict:\n", + " my_dict[\"odd\"] = []\n", + " my_dict[\"odd\"].append(val)\n", " else:\n", - " if not 'even' in my_dict:\n", - " my_dict['even'] = []\n", - " my_dict['even'].append(val)\n", - " \n", + " if not \"even\" in my_dict:\n", + " my_dict[\"even\"] = []\n", + " my_dict[\"even\"].append(val)\n", + "\n", "print(my_dict)" ] }, @@ -293,9 +300,9 @@ "my_dict = defaultdict(list)\n", "for val in data:\n", " if val % 2:\n", - " my_dict['odd'].append(val)\n", + " my_dict[\"odd\"].append(val)\n", " else:\n", - " my_dict['even'].append(val)\n", + " my_dict[\"even\"].append(val)\n", "print(my_dict)" ] }, @@ -317,9 +324,9 @@ "my_dict = defaultdict(int)\n", "for val in data:\n", " if val % 2:\n", - " my_dict['odd_count'] += 1\n", + " my_dict[\"odd_count\"] += 1\n", " else:\n", - " my_dict['even_count'] += 1\n", + " my_dict[\"even_count\"] += 1\n", "print(my_dict)" ] } diff --git a/notebooks/intermediate/notebooks/idiomatic_dicts.ipynb b/notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb similarity index 87% rename from notebooks/intermediate/notebooks/idiomatic_dicts.ipynb rename to notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb index e8470b1..0cccc10 100644 --- a/notebooks/intermediate/notebooks/idiomatic_dicts.ipynb +++ b/notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb @@ -21,7 +21,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'a': 1, 'b': 2, 'c': 3}" + "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}" ] }, { @@ -37,10 +37,10 @@ "metadata": {}, "outputs": [], "source": [ - "if 'g' in my_dict:\n", - " value = my_dict['g']\n", + "if \"g\" in my_dict:\n", + " value = my_dict[\"g\"]\n", "else:\n", - " value = 'some default value'\n", + " value = \"some default value\"\n", "print(value)" ] }, @@ -58,9 +58,9 @@ "outputs": [], "source": [ "try:\n", - " value = my_dict['g']\n", + " value = my_dict[\"g\"]\n", "except KeyError:\n", - " value = 'some default value'\n", + " value = \"some default value\"\n", "print(value)" ] }, @@ -77,7 +77,7 @@ "metadata": {}, "outputs": [], "source": [ - "value = my_dict.get('g', 'some default value')\n", + "value = my_dict.get(\"g\", \"some default value\")\n", "print(value)" ] }, @@ -94,7 +94,7 @@ "metadata": {}, "outputs": [], "source": [ - "value = my_dict.get('g')\n", + "value = my_dict.get(\"g\")\n", "print(value is None)" ] }, @@ -118,15 +118,15 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'a': 1, 'b': 2, 'c': 3}\n", + "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}\n", "\n", - "key = 'g'\n", + "key = \"g\"\n", "if key in my_dict:\n", " value = my_dict[key]\n", "else:\n", - " value = 'some default value'\n", + " value = \"some default value\"\n", " my_dict[key] = value\n", - " \n", + "\n", "print(value)\n", "print(my_dict)" ] @@ -144,10 +144,10 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'a': 1, 'b': 2, 'c': 3}\n", + "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}\n", "\n", - "key = 'g'\n", - "value = my_dict.setdefault(key, 'some default value')\n", + "key = \"g\"\n", + "value = my_dict.setdefault(key, \"some default value\")\n", "\n", "print(value)\n", "print(my_dict)" @@ -219,8 +219,8 @@ "metadata": {}, "outputs": [], "source": [ - "keys = ('a', 'b', 'c')\n", - "values = [True, 100, 'John Doe']" + "keys = (\"a\", \"b\", \"c\")\n", + "values = [True, 100, \"John Doe\"]" ] }, { @@ -277,7 +277,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_dict = {'age': 83, 'is gangster': True, 'name': 'John Doe'}" + "my_dict = {\"age\": 83, \"is gangster\": True, \"name\": \"John Doe\"}" ] }, { @@ -295,7 +295,7 @@ "source": [ "for key in my_dict:\n", " val = my_dict[key]\n", - " print('key: {:15s} value: {}'.format(key, val))" + " print(\"key: {:15s} value: {}\".format(key, val))" ] }, { @@ -312,7 +312,7 @@ "outputs": [], "source": [ "for key, val in my_dict.items():\n", - " print('key: {:15s} value: {}'.format(key, val))" + " print(\"key: {:15s} value: {}\".format(key, val))" ] } ], diff --git a/notebooks/intermediate/notebooks/idiomatic_misc1.ipynb b/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb similarity index 82% rename from notebooks/intermediate/notebooks/idiomatic_misc1.ipynb rename to notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb index 89531a0..8b9c642 100644 --- a/notebooks/intermediate/notebooks/idiomatic_misc1.ipynb +++ b/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb @@ -39,31 +39,31 @@ "# list\n", "square_roots_list = []\n", "for val in original_data:\n", - " square_root = val**(1/2) \n", + " square_root = val ** (1 / 2)\n", " square_roots_list.append(square_root)\n", "print(square_roots_list)\n", "\n", "# set\n", "square_roots_set = set()\n", "for val in original_data:\n", - " square_root = val**(1/2) \n", + " square_root = val ** (1 / 2)\n", " square_roots_set.add(square_root)\n", "print(square_roots_set)\n", "\n", "# dict\n", "square_roots_dict = {}\n", "for val in original_data:\n", - " square_root = val**(1/2) \n", + " square_root = val ** (1 / 2)\n", " square_roots_dict[val] = square_root\n", - "print(square_roots_dict) \n", + "print(square_roots_dict)\n", "\n", "# dict with a condition\n", "integer_square_roots_dict = {}\n", "for val in original_data:\n", - " square_root = val**(1/2)\n", + " square_root = val ** (1 / 2)\n", " if square_root.is_integer():\n", " integer_square_roots_dict[val] = square_root\n", - "print(integer_square_roots_dict) " + "print(integer_square_roots_dict)" ] }, { @@ -86,18 +86,17 @@ "metadata": {}, "outputs": [], "source": [ - "square_roots_list = [val**(1/2) for val in original_data]\n", + "square_roots_list = [val ** (1 / 2) for val in original_data]\n", "print(square_roots_list)\n", "\n", - "square_roots_set = {val**(1/2) for val in original_data}\n", + "square_roots_set = {val ** (1 / 2) for val in original_data}\n", "print(square_roots_set)\n", "\n", - "square_roots_dict = {val: val**(1/2) for val in original_data}\n", + "square_roots_dict = {val: val ** (1 / 2) for val in original_data}\n", "print(square_roots_dict)\n", "\n", "integer_square_roots_dict = {\n", - " val: val**(1/2)\n", - " for val in original_data if (val**(1/2)).is_integer()\n", + " val: val ** (1 / 2) for val in original_data if (val ** (1 / 2)).is_integer()\n", "}\n", "print(integer_square_roots_dict)" ] @@ -115,7 +114,7 @@ "metadata": {}, "outputs": [], "source": [ - "name = 'John Doe'" + "name = \"John Doe\"" ] }, { @@ -131,8 +130,8 @@ "metadata": {}, "outputs": [], "source": [ - "if name == 'John' or name == 'Doe' or name == 'John Doe':\n", - " print('This seems to be our guy')" + "if name == \"John\" or name == \"Doe\" or name == \"John Doe\":\n", + " print(\"This seems to be our guy\")" ] }, { @@ -148,8 +147,8 @@ "metadata": {}, "outputs": [], "source": [ - "if name in ('John', 'Doe', 'John Doe'):\n", - " print('This seems to be our guy')" + "if name in (\"John\", \"Doe\", \"John Doe\"):\n", + " print(\"This seems to be our guy\")" ] }, { @@ -182,7 +181,7 @@ "outputs": [], "source": [ "if b > a and c > b and d > c:\n", - " print('from lowest to highest: a, b, c, d')" + " print(\"from lowest to highest: a, b, c, d\")" ] }, { @@ -199,7 +198,7 @@ "outputs": [], "source": [ "if a < b < c < d:\n", - " print('from lowest to highest: a, b, c, d')" + " print(\"from lowest to highest: a, b, c, d\")" ] }, { @@ -223,11 +222,11 @@ "zero = 0\n", "false = False\n", "none = None\n", - "my_str = ''\n", + "my_str = \"\"\n", "\n", "# Basically the rest are truthy\n", "# for example:\n", - "my_second_list = ['foo']" + "my_second_list = [\"foo\"]" ] }, { @@ -244,19 +243,19 @@ "outputs": [], "source": [ "if len(my_list) == 0:\n", - " print('Empty list is so empty')\n", - " \n", + " print(\"Empty list is so empty\")\n", + "\n", "if not len(my_dict):\n", - " print('Empty dict is also very empty')\n", - " \n", + " print(\"Empty dict is also very empty\")\n", + "\n", "if not len(my_set) and not len(my_tuple):\n", - " print('Same goes for sets and tuples')\n", - " \n", + " print(\"Same goes for sets and tuples\")\n", + "\n", "if not bool(zero) and not bool(false) and not bool(none) and len(my_str) == 0:\n", - " print('These are also falsy')\n", - " \n", + " print(\"These are also falsy\")\n", + "\n", "if len(my_second_list) > 0:\n", - " print('This should be true')" + " print(\"This should be true\")" ] }, { @@ -273,19 +272,19 @@ "outputs": [], "source": [ "if not my_list:\n", - " print('Empty list is so empty')\n", - " \n", + " print(\"Empty list is so empty\")\n", + "\n", "if not my_dict:\n", - " print('Empty dict is also very empty')\n", - " \n", + " print(\"Empty dict is also very empty\")\n", + "\n", "if not my_set and not my_tuple:\n", - " print('Same goes for sets and tuples')\n", - " \n", + " print(\"Same goes for sets and tuples\")\n", + "\n", "if not zero and not false and not none and not my_str:\n", - " print('These are also falsy')\n", - " \n", + " print(\"These are also falsy\")\n", + "\n", "if my_second_list:\n", - " print('This should be true')" + " print(\"This should be true\")" ] }, { @@ -301,7 +300,7 @@ "metadata": {}, "outputs": [], "source": [ - "example_collection = ['a', True, 'Python is cool', 123, 0]" + "example_collection = [\"a\", True, \"Python is cool\", 123, 0]" ] }, { @@ -328,8 +327,8 @@ " if not val:\n", " all_values_truthy = False\n", " break\n", - " \n", - "print('any truthy: {}, all truthy: {}'.format(any_value_truthy, all_values_truthy))" + "\n", + "print(\"any truthy: {}, all truthy: {}\".format(any_value_truthy, all_values_truthy))" ] }, { @@ -347,7 +346,7 @@ "source": [ "any_value_truthy = any(example_collection)\n", "all_values_truthy = all(example_collection)\n", - "print('any truthy: {}, all truthy: {}'.format(any_value_truthy, all_values_truthy))" + "print(\"any truthy: {}, all truthy: {}\".format(any_value_truthy, all_values_truthy))" ] }, { @@ -377,9 +376,9 @@ "some_condition = True # just a dummy condition\n", "\n", "if some_condition:\n", - " variable = 'John'\n", + " variable = \"John\"\n", "else:\n", - " variable = 'Doe'\n", + " variable = \"Doe\"\n", "print(variable)" ] }, @@ -396,7 +395,7 @@ "metadata": {}, "outputs": [], "source": [ - "variable = 'John' if some_condition else 'Doe'\n", + "variable = \"John\" if some_condition else \"Doe\"\n", "print(variable)" ] }, @@ -415,8 +414,11 @@ "outputs": [], "source": [ "def show_person_details(name, is_gangster, is_hacker, age):\n", - " print('name: {}, gangster: {}, hacker: {}, age: {}'.format(\n", - " name, is_gangster, is_hacker, age))" + " print(\n", + " \"name: {}, gangster: {}, hacker: {}, age: {}\".format(\n", + " name, is_gangster, is_hacker, age\n", + " )\n", + " )" ] }, { @@ -432,7 +434,7 @@ "metadata": {}, "outputs": [], "source": [ - "show_person_details('John Doe', True, False, 83)" + "show_person_details(\"John Doe\", True, False, 83)" ] }, { @@ -448,7 +450,7 @@ "metadata": {}, "outputs": [], "source": [ - "show_person_details('John Doe', is_gangster=True, is_hacker=False, age=83)" + "show_person_details(\"John Doe\", is_gangster=True, is_hacker=False, age=83)" ] }, { @@ -465,14 +467,15 @@ "metadata": {}, "outputs": [], "source": [ - "def func_with_loads_of_args(arg1, *, arg2=None, arg3=None, arg4=None, arg5='boom'):\n", + "def func_with_loads_of_args(arg1, *, arg2=None, arg3=None, arg4=None, arg5=\"boom\"):\n", " pass\n", "\n", + "\n", "# This won't work because only keyword arguments allowed after *\n", - "#func_with_loads_of_args('John Doe', 1, 2)\n", + "# func_with_loads_of_args('John Doe', 1, 2)\n", "\n", "# This is ok\n", - "func_with_loads_of_args('John Doe', arg4='foo', arg5='bar', arg2='foo bar')" + "func_with_loads_of_args(\"John Doe\", arg4=\"foo\", arg5=\"bar\", arg2=\"foo bar\")" ] }, { diff --git a/notebooks/intermediate/notebooks/idiomatic_misc2.ipynb b/notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb similarity index 81% rename from notebooks/intermediate/notebooks/idiomatic_misc2.ipynb rename to notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb index 08a48d5..7500f1b 100644 --- a/notebooks/intermediate/notebooks/idiomatic_misc2.ipynb +++ b/notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb @@ -20,7 +20,7 @@ "metadata": {}, "outputs": [], "source": [ - "names = ('John', 'Lisa', 'Terminator', 'Python')" + "names = (\"John\", \"Lisa\", \"Terminator\", \"Python\")" ] }, { @@ -38,7 +38,7 @@ "source": [ "semicolon_separated = names[0]\n", "for name in names[1:]:\n", - " semicolon_separated += ';' + name\n", + " semicolon_separated += \";\" + name\n", "print(semicolon_separated)" ] }, @@ -55,7 +55,7 @@ "metadata": {}, "outputs": [], "source": [ - "semicolon_separated = ';'.join(names)\n", + "semicolon_separated = \";\".join(names)\n", "print(semicolon_separated)" ] }, @@ -79,7 +79,7 @@ "source": [ "a = 0\n", "b = None\n", - "c = 'John Doe'" + "c = \"John Doe\"" ] }, { @@ -95,7 +95,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_variable = 'default value'\n", + "my_variable = \"default value\"\n", "if a:\n", " my_variable = a\n", "elif b:\n", @@ -118,7 +118,7 @@ "metadata": {}, "outputs": [], "source": [ - "my_variable = a or b or c or 'default value'\n", + "my_variable = a or b or c or \"default value\"\n", "print(my_variable)" ] }, @@ -145,18 +145,18 @@ "exception_occured = False\n", "try:\n", " # here would be the logic of your master piece\n", - " \n", + "\n", " bad_calculation = 1 / 0\n", - " \n", + "\n", "except ValueError as e:\n", - " print('Oh boi, some value error: {}'.format(e))\n", + " print(\"Oh boi, some value error: {}\".format(e))\n", " exception_occured = True\n", "except Exception as e:\n", - " print('Oh boi, something bad happened: {}'.format(e))\n", + " print(\"Oh boi, something bad happened: {}\".format(e))\n", " exception_occured = True\n", - " \n", + "\n", "if not exception_occured:\n", - " print('All went well!')" + " print(\"All went well!\")" ] }, { @@ -174,15 +174,15 @@ "source": [ "try:\n", " # here would be the logic of your master piece\n", - " \n", + "\n", " bad_calculation = 1 / 0\n", - " \n", + "\n", "except ValueError as e:\n", - " print('Oh boi, some keyerror: {}'.format(e))\n", + " print(\"Oh boi, some keyerror: {}\".format(e))\n", "except Exception as e:\n", - " print('Oh boi, something bad happened: {}'.format(e))\n", + " print(\"Oh boi, something bad happened: {}\".format(e))\n", "else:\n", - " print('All went well!')" + " print(\"All went well!\")" ] }, { @@ -211,16 +211,17 @@ " # here would be the logic of your master piece\n", " result = 1 / 0\n", " except ZeroDivisionError:\n", - " print('This could be something important that should be done every time')\n", + " print(\"This could be something important that should be done every time\")\n", " return 0\n", " except Exception:\n", - " print('This could be something important that should be done every time')\n", + " print(\"This could be something important that should be done every time\")\n", " return None\n", "\n", - " print('This could be something important that should be done every time')\n", + " print(\"This could be something important that should be done every time\")\n", " return result\n", "\n", - "print('return value: {}'.format(magical_calculation()))" + "\n", + "print(\"return value: {}\".format(magical_calculation()))" ] }, { @@ -245,10 +246,11 @@ " except Exception:\n", " return None\n", " finally:\n", - " print('This could be something important that should be done every time')\n", + " print(\"This could be something important that should be done every time\")\n", " return result\n", "\n", - "print('return value: {}'.format(magical_calculation()))" + "\n", + "print(\"return value: {}\".format(magical_calculation()))" ] }, { @@ -280,11 +282,11 @@ "outputs": [], "source": [ "try:\n", - " some_file = open('tmp.txt', 'w')\n", - " print('the file is now open: {}'.format(not some_file.closed))\n", - " \n", + " some_file = open(\"tmp.txt\", \"w\")\n", + " print(\"the file is now open: {}\".format(not some_file.closed))\n", + "\n", " # here would be some logic\n", - " \n", + "\n", "finally:\n", " some_file.close()\n", " print(\"now it's closed: {}\".format(some_file.closed))" @@ -303,9 +305,9 @@ "metadata": {}, "outputs": [], "source": [ - "with open('tmp.txt', 'w') as some_file:\n", - " print('the file is now open: {}'.format(not some_file.closed))\n", - " \n", + "with open(\"tmp.txt\", \"w\") as some_file:\n", + " print(\"the file is now open: {}\".format(not some_file.closed))\n", + "\n", " # here would be some logic\n", "\n", "print(\"now it's closed: {}\".format(some_file.closed))" @@ -326,19 +328,22 @@ "source": [ "from contextlib import contextmanager\n", "\n", + "\n", "@contextmanager\n", "def my_context():\n", - " print('Entering to my context')\n", + " print(\"Entering to my context\")\n", " yield\n", - " print('Exiting my context')\n", - " \n", + " print(\"Exiting my context\")\n", + "\n", + "\n", "def do_stuff():\n", " with my_context():\n", - " print('Doing stuff')\n", - " \n", - " print('Doing some stuff outside my context')\n", - " \n", - "do_stuff() " + " print(\"Doing stuff\")\n", + "\n", + " print(\"Doing some stuff outside my context\")\n", + "\n", + "\n", + "do_stuff()" ] }, { @@ -416,7 +421,7 @@ "source": [ "value = 0\n", "try:\n", - " value = 1 / 0 # just for demonstrating purposes \n", + " value = 1 / 0 # just for demonstrating purposes\n", "except ZeroDivisionError:\n", " pass\n", "\n", @@ -441,7 +446,7 @@ "value = 0\n", "with suppress(ZeroDivisionError):\n", " value = 1 / 0 # just for demonstrating purposes\n", - " \n", + "\n", "print(value)" ] }, @@ -469,21 +474,21 @@ " def __init__(self, first_name, last_name):\n", " self.first_name = first_name\n", " self.last_name = last_name\n", - " \n", + "\n", " def get_full_name(self):\n", - " return '{} {}'.format(self.first_name, self.last_name)\n", - " \n", + " return \"{} {}\".format(self.first_name, self.last_name)\n", + "\n", " def set_full_name(self, full_name):\n", " parts = full_name.split()\n", " if len(parts) != 2:\n", - " raise ValueError('Sorry, too difficult name')\n", - " \n", - " self.first_name, self.last_name = parts \n", - " \n", - " \n", - "p = Person('John', 'Doe')\n", + " raise ValueError(\"Sorry, too difficult name\")\n", + "\n", + " self.first_name, self.last_name = parts\n", + "\n", + "\n", + "p = Person(\"John\", \"Doe\")\n", "print(p.get_full_name())\n", - "p.set_full_name('Lisa Doe')\n", + "p.set_full_name(\"Lisa Doe\")\n", "print(p.get_full_name())" ] }, @@ -504,23 +509,23 @@ " def __init__(self, first_name, last_name):\n", " self.first_name = first_name\n", " self.last_name = last_name\n", - " \n", + "\n", " @property\n", " def full_name(self):\n", - " return '{} {}'.format(self.first_name, self.last_name)\n", - " \n", + " return \"{} {}\".format(self.first_name, self.last_name)\n", + "\n", " @full_name.setter\n", " def full_name(self, name):\n", " parts = name.split()\n", " if len(parts) != 2:\n", - " raise ValueError('Sorry, too difficult name')\n", - " \n", + " raise ValueError(\"Sorry, too difficult name\")\n", + "\n", " self.first_name, self.last_name = parts\n", "\n", - " \n", - "p = Person('John', 'Doe')\n", + "\n", + "p = Person(\"John\", \"Doe\")\n", "print(p.full_name)\n", - "p.full_name = 'Lisa Doe'\n", + "p.full_name = \"Lisa Doe\"\n", "print(p.full_name)" ] } From 0d6f95ab5cebde0b58640550395561dead1be28a Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 19 Apr 2023 10:23:22 +0300 Subject: [PATCH 09/30] Update links and remove old stuff --- README.md | 71 +++++++++++++++---------------------------------------- 1 file changed, 19 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index 1c9b174..8c8ecd3 100644 --- a/README.md +++ b/README.md @@ -27,25 +27,25 @@ See [contributing](https://github.com/jerry-git/learn-python3/blob/master/CONTRI ## Beginner -1. [Strings](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/strings.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/strings.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/strings_exercise.ipynb) -1. [Numbers](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/numbers.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/numbers.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/numbers_exercise.ipynb) -1. [Conditionals](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/conditionals.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/conditionals.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/conditionals_exercise.ipynb) -1. [Lists](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/lists.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/lists.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/lists_exercise.ipynb) -1. [Dictionaries](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/dictionaries.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/dictionaries.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/dictionaries_exercise.ipynb) -1. [For loops](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/for_loops.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/for_loops.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/for_loops_exercise.ipynb) -1. [Functions](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/functions.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/functions.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/functions_exercise.ipynb) -1. [Testing with pytest - part 1](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/testing1.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/testing1.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/testing1_exercise.ipynb) -1. Recap exercise 1 [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/recap1_exercise.ipynb) -1. [File I\O](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/file_io.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/file_io.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/file_io_exercise.ipynb) -1. [Classes](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/classes.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/classes.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/classes_exercise.ipynb) -1. [Exceptions](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/exceptions.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/exceptions.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/exceptions_exercise.ipynb) -1. [Modules and packages](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/modules_and_packages.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/modules_and_packages.ipynb) -1. [Debugging](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/debugging.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/debugging.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/debugging_exercise.ipynb) -1. [Goodies of the Standard Library - part 1](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/std_lib.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/std_lib.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/std_lib1_exercise.ipynb) -1. [Testing with pytest - part 2](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/testing2.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/testing2.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/testing2_exercise.ipynb) -1. [Virtual environment](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/venv.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/venv.ipynb) -1. [Project structure](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/project_structure.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/project_structure.ipynb) -1. Recap exercise 2 [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/recap2_exercise.ipynb) +1. [Strings](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/01_strings.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/01_strings.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/01_strings_exercise.ipynb) +2. [Numbers](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/02_numbers.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/02_numbers.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/02_numbers_exercise.ipynb) +3. [Conditionals](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/03_conditionals.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/03_conditionals.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/03_conditionals_exercise.ipynb) +4. [Lists](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/04_lists.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/04_lists.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/04_lists_exercise.ipynb) +5. [Dictionaries](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/05_dictionaries.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/05_dictionaries.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/05_dictionaries_exercise.ipynb) +6. [For loops](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/06_for_loops.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/06_for_loops.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/06_for_loops_exercise.ipynb) +7. [Functions](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/07_functions.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/07_functions.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/07_functions_exercise.ipynb) +8. [Testing with pytest - part 1](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/08_testing1.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/08_testing1.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/08_testing1_exercise.ipynb) +9. Recap exercise 1 [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/09_recap1_exercise.ipynb) +10. [File I\O](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/10_file_io.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/10_file_io.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/10_file_io_exercise.ipynb) +11. [Classes](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/11_classes.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/11_classes.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/11_classes_exercise.ipynb) +12. [Exceptions](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/12_exceptions.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/12_exceptions.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/12_exceptions_exercise.ipynb) +13. [Modules and packages](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/13_modules_and_packages.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/13_modules_and_packages.ipynb) +14. [Debugging](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/14_debugging.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/14_debugging.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/14_debugging_exercise.ipynb) +15. [Goodies of the Standard Library - part 1](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/15_std_lib.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/15_std_lib.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/15_std_lib1_exercise.ipynb) +16. [Testing with pytest - part 2](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/16_testing2.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/16_testing2.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/16_testing2_exercise.ipynb) +17. [Virtual environment](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/17_venv.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/17_venv.ipynb) +18. [Project structure](https://jerry-git.github.io/learn-python3/notebooks/beginner/html/18_project_structure.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/notebooks/18_project_structure.ipynb) +19. Recap exercise 2 [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/beginner/exercises/19_recap2_exercise.ipynb) ## Intermediate @@ -61,7 +61,6 @@ Python is a powerful language which contains many features not presented in most #### Step up your `pytest` game 1. [Efficient use of fixtures](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/pytest_fixtures.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/pytest_fixtures.ipynb) -1. Other tips and tricks #### Best practices A list of best development practices for Python projects. Most of the practices listed here are also applicable for other languages, however the presented tooling focuses mainly on Python. @@ -70,38 +69,6 @@ A list of best development practices for Python projects. Most of the practices #### General topics 1. [Goodies of the Standard Library - part 2](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/std_lib2.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/std_lib2.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/exercises/std_lib2_exercise.ipynb) -#### Backlog -* Sets -* Generators -* Decorators -* Context managers -* Playing with attributes -* *, *args, **kwargs -* Command line arguments with click -* OOP - inheritance -* OOP - Abstract Base Classes -* OOP - attrs -* Testing with mocks -* Structuring your tests - - -## Use cases - -#### Playing with the web -* requests -* testing requests with responses -* beautifulsoup4 -* selenium - -#### Communicating with databases -* SQLAlchemy - -#### Working with documents -* excel - * openpyxl -* pdf - * pdfrw / PyPDF2 - ## Credits * Logo: Abdur-Rahmaan Janhangeer, [@Abdur-rahmaanJ](https://github.com/Abdur-rahmaanJ) From 45d6173f1469e99ca9b403c4f94efcc8e41925d0 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 19 Apr 2023 10:27:48 +0300 Subject: [PATCH 10/30] Update contribution guidelines --- CONTRIBUTING.md | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 108f2a3..d93926c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,15 +5,23 @@ If you spot a typo or the content does not make sense in some way, feel free to I am open for enhancement ideas and feature requests. If there's some topic you'd like to see a notebook about, feel free to open an issue and request it there. ## Development +Install development dependencies +``` +pip install -r dev-requirements.txt +``` -#### post_save_hook -* Copy the content of utils/post_save_hook.py to your jupyter_notebook_config.py before making changes to notebooks -* This will setup a post_save_hook which will generate a html version of the notebook automatically when the notebook is saved -* htmls are not generated for exercises +#### Generating html +``` +python scripts/notebook_to_html.py +``` #### Testing -* Travis CI will make sure that the code cells in the notebooks can be executed -* You test the same locally by: - * install tox by: `pip install tox` - * run tox: `tox` -* Tests are not run for exercises (because the code in the exercise cells is usually intentionally incomplete) \ No newline at end of file +``` +pytest --nbval notebooks +``` + +#### pre-commit +``` +pre-commit install +``` +and it'll automatically run all the pre-commit hooks for each commit. From 33150e098d4c401c53f9b927d7a858f5e170af73 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Wed, 19 Apr 2023 10:33:55 +0300 Subject: [PATCH 11/30] Add CI workflow --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a2afda0 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + pull_request: + push: + branches: + - "**" + +jobs: + checks: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + python-version: [ "3.10", "3.11" ] + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - run: pip install -r dev-requirements.txt + - run: pre-commit run -a + - run: pytest --nbval notebooks From 5befce8e92c0c0dc0353b18af3bd48d712a562f4 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Thu, 20 Apr 2023 10:13:38 +0300 Subject: [PATCH 12/30] Workaround to get ipytest play nicely with 3.11 See https://github.com/chmp/ipytest/issues/93 --- .../beginner/notebooks/08_testing1.ipynb | 7 +------ .../beginner/notebooks/16_testing2.ipynb | 16 +++------------ .../notebooks/01_pytest_fixtures.ipynb | 20 +++++++------------ 3 files changed, 11 insertions(+), 32 deletions(-) diff --git a/notebooks/beginner/notebooks/08_testing1.ipynb b/notebooks/beginner/notebooks/08_testing1.ipynb index 562ab40..0e921ad 100644 --- a/notebooks/beginner/notebooks/08_testing1.ipynb +++ b/notebooks/beginner/notebooks/08_testing1.ipynb @@ -78,7 +78,6 @@ "metadata": {}, "outputs": [], "source": [ - "# This would be in your e.g. implementation.py\n", "def sum_of_three_numbers(num1, num2, num3):\n", " return num1 + num2 + num3" ] @@ -102,11 +101,7 @@ "outputs": [], "source": [ "%%ipytest\n", - "# Mention this at the top of cells which contain test(s)\n", - "# This is only required for running pytest in Jupyter notebooks\n", "\n", - "\n", - "# This would be in your test_implementation.py\n", "def test_sum_of_three_numbers():\n", " # 1. Setup the variables used in the test\n", " num1 = 2\n", @@ -144,7 +139,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/16_testing2.ipynb b/notebooks/beginner/notebooks/16_testing2.ipynb index d0e72e2..06b013f 100644 --- a/notebooks/beginner/notebooks/16_testing2.ipynb +++ b/notebooks/beginner/notebooks/16_testing2.ipynb @@ -40,7 +40,6 @@ "metadata": {}, "outputs": [], "source": [ - "# This would be e.g. in person.py\n", "class Person:\n", " def __init__(self, first_name, last_name, age):\n", " self.first_name = first_name\n", @@ -74,7 +73,6 @@ "metadata": {}, "outputs": [], "source": [ - "# This would be in either conftest.py or test_person.py\n", "import pytest\n", "\n", "\n", @@ -99,7 +97,7 @@ "source": [ "%%ipytest\n", "\n", - "# These would be in test_person.py\n", + "\n", "def test_full_name(default_person): # Note: we use fixture as an argument of the test case\n", " result = default_person.full_name\n", " assert result == 'John Doe'\n", @@ -147,7 +145,6 @@ "metadata": {}, "outputs": [], "source": [ - "# This would be e.g. in string_manipulate.py\n", "def replace_names(original_str, new_name):\n", " \"\"\"Replaces names (uppercase words) of original_str by new_name\"\"\"\n", " words = original_str.split()\n", @@ -170,7 +167,7 @@ "source": [ "%%ipytest\n", "\n", - "# This would be in your test module\n", + "\n", "@pytest.mark.parametrize(\"original,new_name,expected\", [\n", " ('this is Lisa', 'John Doe', 'this is John Doe'),\n", " ('how about Frank and Amy', 'John', 'how about John and John'),\n", @@ -180,13 +177,6 @@ " result = replace_names(original, new_name)\n", " assert result == expected" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { @@ -205,7 +195,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb index 09f5ca0..fcc27e6 100644 --- a/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb +++ b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb @@ -83,23 +83,18 @@ "metadata": {}, "outputs": [], "source": [ + "%%ipytest -s\n", + "\n", + "\n", "@pytest.fixture\n", "def my_fixture():\n", " print(\"\\nmy_fixture is used\")\n", - "\n", + " \n", "\n", "@pytest.fixture\n", "def other_fixture():\n", - " return \"FOO\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%%ipytest -s\n", + " return \"FOO\"\n", + "\n", "\n", "@pytest.mark.usefixtures('my_fixture')\n", "class TestMyStuff:\n", @@ -258,7 +253,6 @@ "metadata": {}, "outputs": [], "source": [ - "# scope is function also by default\n", "@pytest.fixture(scope=\"function\")\n", "def func_fixture():\n", " print(\"\\nfunc\")\n", @@ -373,7 +367,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.11.0" } }, "nbformat": 4, From 407dc6d28c99fb44c66897b4353de99b7da20849 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Thu, 20 Apr 2023 10:20:55 +0300 Subject: [PATCH 13/30] Update ipytest things --- .../exercises/08_testing1_exercise.ipynb | 15 ++++++++------- .../exercises/16_testing2_exercise.ipynb | 16 +++++++++------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/notebooks/beginner/exercises/08_testing1_exercise.ipynb b/notebooks/beginner/exercises/08_testing1_exercise.ipynb index ea7219c..98512b2 100644 --- a/notebooks/beginner/exercises/08_testing1_exercise.ipynb +++ b/notebooks/beginner/exercises/08_testing1_exercise.ipynb @@ -6,16 +6,17 @@ "metadata": {}, "outputs": [], "source": [ - "# Required boilerplate\n", + "# Let's make sure pytest and ipytest packages are installed\n", + "# ipytest is required for running pytest inside Jupyter notebooks\n", "import sys\n", "\n", "!{sys.executable} -m pip install pytest\n", "!{sys.executable} -m pip install ipytest\n", "\n", - "import ipytest.magics\n", - "import pytest\n", + "# These are needed for running pytest inside Jupyter notebooks\n", + "import ipytest\n", "\n", - "__file__ = \"testing1_exercise.ipynb\"" + "ipytest.autoconfig()" ] }, { @@ -50,7 +51,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean]\n", + "%%ipytest\n", "\n", "def test_get_divisible_by_five():\n", " # Your implementation here\n" @@ -59,7 +60,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -73,7 +74,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/exercises/16_testing2_exercise.ipynb b/notebooks/beginner/exercises/16_testing2_exercise.ipynb index d3862db..a7a2b3b 100644 --- a/notebooks/beginner/exercises/16_testing2_exercise.ipynb +++ b/notebooks/beginner/exercises/16_testing2_exercise.ipynb @@ -6,16 +6,18 @@ "metadata": {}, "outputs": [], "source": [ - "# Required boilerplate\n", + "# Let's make sure pytest and ipytest packages are installed\n", + "# ipytest is required for running pytest inside Jupyter notebooks\n", "import sys\n", "\n", "!{sys.executable} -m pip install pytest\n", "!{sys.executable} -m pip install ipytest\n", "\n", - "import ipytest.magics\n", + "# These are needed for running pytest inside Jupyter notebooks\n", + "import ipytest\n", "import pytest\n", "\n", - "__file__ = \"testing2_exercise.ipynb\"" + "ipytest.autoconfig()" ] }, { @@ -83,7 +85,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean]\n", + "%%ipytest\n", "\n", "\n", "@pytest.____\n", @@ -171,7 +173,7 @@ "metadata": {}, "outputs": [], "source": [ - "%%run_pytest[clean]\n", + "%%ipytest\n", "\n", "# Your implementation here\n" ] @@ -179,7 +181,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -193,7 +195,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, From 252d70bdaee4239b4857e636961a8ce2f77b6354 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Fri, 21 Apr 2023 13:41:52 +0300 Subject: [PATCH 14/30] Add nbqa to dev deps --- dev-requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/dev-requirements.txt b/dev-requirements.txt index e3f4c05..9e30ba2 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -1,5 +1,6 @@ black[jupyter] jupyter +nbqa[toolchain] nbval pre-commit pytest From 5a0793db03bd80e894aa9ac19fadb6c1ae00e546 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Fri, 21 Apr 2023 13:42:01 +0300 Subject: [PATCH 15/30] Add hook for pyupgrade --- .pre-commit-config.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a2296f5..7c09ca9 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,3 +11,8 @@ repos: entry: black language: system files: \.(py|ipynb)$ + - id: pyupgrade + name: pyupgrade + entry: nbqa pyupgrade --py310-plus + language: system + files: \.(py|ipynb)$ From 52ca70b866df59b1aa21c50784b828cfbc069cd5 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Fri, 21 Apr 2023 13:45:36 +0300 Subject: [PATCH 16/30] Pyupgrade 3.10+ --- .../exercises/01_strings_exercise.ipynb | 4 +- .../exercises/03_conditionals_exercise.ipynb | 10 +-- .../exercises/16_testing2_exercise.ipynb | 4 +- notebooks/beginner/notebooks/01_strings.ipynb | 33 +++++---- notebooks/beginner/notebooks/02_numbers.ipynb | 10 +-- .../beginner/notebooks/03_conditionals.ipynb | 67 ++++++------------- notebooks/beginner/notebooks/04_lists.ipynb | 32 ++++----- .../beginner/notebooks/05_dictionaries.ipynb | 46 ++++++------- .../beginner/notebooks/06_for_loops.ipynb | 4 +- .../beginner/notebooks/07_functions.ipynb | 8 +-- notebooks/beginner/notebooks/10_file_io.ipynb | 16 ++--- notebooks/beginner/notebooks/11_classes.ipynb | 20 +++--- .../beginner/notebooks/12_exceptions.ipynb | 14 ++-- .../beginner/notebooks/14_debugging.ipynb | 6 +- notebooks/beginner/notebooks/15_std_lib.ipynb | 36 +++++----- .../beginner/notebooks/16_testing2.ipynb | 2 +- .../exercises/01_std_lib2_exercise.ipynb | 2 +- .../05_idiomatic_python_exercise.ipynb | 2 +- .../notebooks/01_idiomatic_loops.ipynb | 2 +- .../notebooks/01_pytest_fixtures.ipynb | 2 +- .../intermediate/notebooks/01_std_lib2.ipynb | 14 ++-- .../notebooks/02_idiomatic_dicts.ipynb | 4 +- .../notebooks/03_idiomatic_misc1.ipynb | 4 +- .../notebooks/04_idiomatic_misc2.ipynb | 24 +++---- 24 files changed, 167 insertions(+), 199 deletions(-) diff --git a/notebooks/beginner/exercises/01_strings_exercise.ipynb b/notebooks/beginner/exercises/01_strings_exercise.ipynb index 66a97be..cf94527 100644 --- a/notebooks/beginner/exercises/01_strings_exercise.ipynb +++ b/notebooks/beginner/exercises/01_strings_exercise.ipynb @@ -84,7 +84,7 @@ }, "outputs": [], "source": [ - "print(\"pretty: {}\".format(pretty))\n", + "print(f\"pretty: {pretty}\")\n", "assert pretty == \"Title Of My New Book\"" ] }, @@ -127,7 +127,7 @@ }, "outputs": [], "source": [ - "print(\"sentence: {}\".format(sentence))\n", + "print(f\"sentence: {sentence}\")\n", "assert sentence == \"Learning Python is fun!\"" ] } diff --git a/notebooks/beginner/exercises/03_conditionals_exercise.ipynb b/notebooks/beginner/exercises/03_conditionals_exercise.ipynb index 061c2c1..9052e70 100644 --- a/notebooks/beginner/exercises/03_conditionals_exercise.ipynb +++ b/notebooks/beginner/exercises/03_conditionals_exercise.ipynb @@ -26,19 +26,19 @@ "outputs": [], "source": [ "if ____:\n", - " print('Name \"{}\" is more than 20 chars long'.format(name))\n", + " print(f'Name \"{name}\" is more than 20 chars long')\n", " length_description = \"long\"\n", "elif ____:\n", - " print('Name \"{}\" is more than 15 chars long'.format(name))\n", + " print(f'Name \"{name}\" is more than 15 chars long')\n", " length_description = \"semi long\"\n", "elif ____:\n", - " print('Name \"{}\" is more than 10 chars long'.format(name))\n", + " print(f'Name \"{name}\" is more than 10 chars long')\n", " length_description = \"semi long\"\n", "elif ____:\n", - " print('Name \"{}\" is 8, 9 or 10 chars long'.format(name))\n", + " print(f'Name \"{name}\" is 8, 9 or 10 chars long')\n", " length_description = \"semi short\"\n", "else:\n", - " print('Name \"{}\" is a short name'.format(name))\n", + " print(f'Name \"{name}\" is a short name')\n", " length_description = \"short\"" ] }, diff --git a/notebooks/beginner/exercises/16_testing2_exercise.ipynb b/notebooks/beginner/exercises/16_testing2_exercise.ipynb index a7a2b3b..c1e426f 100644 --- a/notebooks/beginner/exercises/16_testing2_exercise.ipynb +++ b/notebooks/beginner/exercises/16_testing2_exercise.ipynb @@ -60,14 +60,14 @@ "\n", " def complete(self, number):\n", " if number not in self._todo:\n", - " raise TodoNotFound(\"{} not in todos\".format(number))\n", + " raise TodoNotFound(f\"{number} not in todos\")\n", "\n", " task = self._todo.pop(number)\n", " self._done[number] = task\n", "\n", " def remove(self, number):\n", " if number not in self._todo:\n", - " raise TodoNotFound(\"{} not in todos\".format(number))\n", + " raise TodoNotFound(f\"{number} not in todos\")\n", "\n", " del self._todo[number]" ] diff --git a/notebooks/beginner/notebooks/01_strings.ipynb b/notebooks/beginner/notebooks/01_strings.ipynb index fdbb05a..d2841f8 100644 --- a/notebooks/beginner/notebooks/01_strings.ipynb +++ b/notebooks/beginner/notebooks/01_strings.ipynb @@ -126,7 +126,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## `str.format()`" + "## f-strings" ] }, { @@ -135,8 +135,11 @@ "metadata": {}, "outputs": [], "source": [ - "secret = \"{} is cool\".format(\"Python\")\n", - "print(secret)" + "first_name = \"John\"\n", + "last_name = \"Doe\"\n", + "age = 88\n", + "print(f\"My name is {first_name} {last_name}, you can call me {first_name}.\")\n", + "print(f\"I'm {age} years old.\")" ] }, { @@ -145,13 +148,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"My name is {} {}, you can call me {}.\".format(\"John\", \"Doe\", \"John\"))\n", - "# is the same as:\n", - "print(\n", - " \"My name is {first} {family}, you can call me {first}.\".format(\n", - " first=\"John\", family=\"Doe\"\n", - " )\n", - ")" + "print(f\"Use '=' to also print the variable name like this: {age=}\")" ] }, { @@ -179,14 +176,14 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"Some cool python libraries: {}\".format(cool_python_libs))" + "print(f\"Some cool python libraries: {cool_python_libs}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Alternatives (not as [Pythonic](http://docs.python-guide.org/en/latest/writing/style/#idioms) and [slower](https://waymoot.org/home/python_string/)):" + "Alternative (not as [Pythonic](http://docs.python-guide.org/en/latest/writing/style/#idioms) and [slower](https://waymoot.org/home/python_string/)):" ] }, { @@ -196,12 +193,12 @@ "outputs": [], "source": [ "cool_python_libs = pandas + \", \" + numpy + \", \" + requests\n", - "print(\"Some cool python libraries: {}\".format(cool_python_libs))\n", + "print(f\"Some cool python libraries: {cool_python_libs}\")\n", "\n", "cool_python_libs = pandas\n", "cool_python_libs += \", \" + numpy\n", "cool_python_libs += \", \" + requests\n", - "print(\"Some cool python libraries: {}\".format(cool_python_libs))" + "print(f\"Some cool python libraries: {cool_python_libs}\")" ] }, { @@ -263,8 +260,8 @@ "ugly_formatted = \" \\n \\t Some story to tell \"\n", "stripped = ugly_formatted.strip()\n", "\n", - "print(\"ugly: {}\".format(ugly_formatted))\n", - "print(\"stripped: {}\".format(ugly_formatted.strip()))" + "print(f\"ugly: {ugly_formatted}\")\n", + "print(f\"stripped: {stripped}\")" ] }, { @@ -370,7 +367,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -384,7 +381,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/02_numbers.ipynb b/notebooks/beginner/notebooks/02_numbers.ipynb index 45af1a7..4fd6678 100644 --- a/notebooks/beginner/notebooks/02_numbers.ipynb +++ b/notebooks/beginner/notebooks/02_numbers.ipynb @@ -21,7 +21,7 @@ "outputs": [], "source": [ "my_int = 6\n", - "print(\"value: {}, type: {}\".format(my_int, type(my_int)))" + "print(f\"value: {my_int}, type: {type(my_int)}\")" ] }, { @@ -38,7 +38,7 @@ "outputs": [], "source": [ "my_float = float(my_int)\n", - "print(\"value: {}, type: {}\".format(my_float, type(my_float)))" + "print(f\"value: {my_float}, type: {type(my_float)}\")" ] }, { @@ -135,7 +135,7 @@ "source": [ "from_float = Decimal(0.1)\n", "from_str = Decimal(\"0.1\")\n", - "print(\"from float: {}\\nfrom string: {}\".format(from_float, from_str))" + "print(f\"from float: {from_float}\\nfrom string: {from_str}\")" ] }, { @@ -170,7 +170,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -184,7 +184,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/03_conditionals.ipynb b/notebooks/beginner/notebooks/03_conditionals.ipynb index 9600954..4958b96 100644 --- a/notebooks/beginner/notebooks/03_conditionals.ipynb +++ b/notebooks/beginner/notebooks/03_conditionals.ipynb @@ -1,30 +1,5 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from IPython.display import HTML\n", - "\n", - "HTML(\n", - " \"\"\"\n", - "
\"\"\"\n", - ")" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -52,7 +27,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"type of True and False: {}\".format(type(True)))" + "print(f\"type of True and False: {type(True)}\")" ] }, { @@ -61,9 +36,9 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"0: {}, 1: {}\".format(bool(0), bool(1)))\n", - "print(\"empty list: {}, list with values: {}\".format(bool([]), bool([\"woop\"])))\n", - "print(\"empty dict: {}, dict with values: {}\".format(bool({}), bool({\"Python\": \"cool\"})))" + "print(f\"0: {bool(0)}, 1: {bool(1)}\")\n", + "print(f\"empty list: {bool([])}, list with values: {bool(['woop'])}\")\n", + "print(f\"empty dict: {bool({})}, dict with values: {bool({'Python': 'cool'})}\")" ] }, { @@ -79,16 +54,16 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"1 == 0: {}\".format(1 == 0))\n", - "print(\"1 != 0: {}\".format(1 != 0))\n", - "print(\"1 > 0: {}\".format(1 > 0))\n", - "print(\"1 > 1: {}\".format(1 > 1))\n", - "print(\"1 < 0: {}\".format(1 < 0))\n", - "print(\"1 < 1: {}\".format(1 < 1))\n", - "print(\"1 >= 0: {}\".format(1 >= 0))\n", - "print(\"1 >= 1: {}\".format(1 >= 1))\n", - "print(\"1 <= 0: {}\".format(1 <= 0))\n", - "print(\"1 <= 1: {}\".format(1 <= 1))" + "print(f\"{1 == 0}\")\n", + "print(f\"{1 != 0}\")\n", + "print(f\"{1 > 0}\")\n", + "print(f\"{1 > 1}\")\n", + "print(f\"{1 < 0}\")\n", + "print(f\"{1 < 1}\")\n", + "print(f\"{1 >= 0}\")\n", + "print(f\"{1 >= 1}\")\n", + "print(f\"{1 <= 0}\")\n", + "print(f\"{1 <= 1}\")" ] }, { @@ -104,7 +79,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"1 <= 2 <= 3: {}\".format(1 <= 2 <= 3))" + "print(f\"{1 <= 2 <= 3}\")" ] }, { @@ -132,8 +107,8 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"Python and java are both cool: {}\".format(python_is_cool and java_is_cool))\n", - "print(\"secret_value and python_is_cool: {}\".format(secret_value and python_is_cool))" + "print(f\"Python and java are both cool: {python_is_cool and java_is_cool}\")\n", + "print(f\"secret_value and python_is_cool: {secret_value and python_is_cool}\")" ] }, { @@ -142,8 +117,8 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"Python or java is cool: {}\".format(python_is_cool or java_is_cool))\n", - "print('1 >= 1.1 or 2 < float(\"1.4\"): {}'.format(1 >= 1.1 or 2 < float(\"1.4\")))" + "print(f\"Python or java is cool: {python_is_cool or java_is_cool}\")\n", + "print(f\"{1 >= 1.1 or 2 < 1.4}\")" ] }, { @@ -152,7 +127,7 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"Java is not cool: {}\".format(not java_is_cool))" + "print(f\"Java is not cool: {not java_is_cool}\")" ] }, { @@ -310,7 +285,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/04_lists.ipynb b/notebooks/beginner/notebooks/04_lists.ipynb index 2820efd..6949ef2 100644 --- a/notebooks/beginner/notebooks/04_lists.ipynb +++ b/notebooks/beginner/notebooks/04_lists.ipynb @@ -14,7 +14,7 @@ "outputs": [], "source": [ "my_empty_list = []\n", - "print(\"empty list: {}, type: {}\".format(my_empty_list, type(my_empty_list)))" + "print(f\"empty list: {my_empty_list}, type: {type(my_empty_list)}\")" ] }, { @@ -25,7 +25,7 @@ "source": [ "list_of_ints = [1, 2, 6, 7]\n", "list_of_misc = [0.2, 5, \"Python\", \"is\", \"still fun\", \"!\"]\n", - "print(\"lengths: {} and {}\".format(len(list_of_ints), len(list_of_misc)))" + "print(f\"lengths: {len(list_of_ints)} and {len(list_of_misc)}\")" ] }, { @@ -53,8 +53,8 @@ "outputs": [], "source": [ "coordinates = [[12.0, 13.3], [0.6, 18.0], [88.0, 1.1]] # two dimensional\n", - "print(\"first coordinate: {}\".format(coordinates[0]))\n", - "print(\"second element of first coordinate: {}\".format(coordinates[0][1]))" + "print(f\"first coordinate: {coordinates[0]}\")\n", + "print(f\"second element of first coordinate: {coordinates[0][1]}\")" ] }, { @@ -123,7 +123,7 @@ "original = [1, 2, 3]\n", "modified = original\n", "modified[0] = 99\n", - "print(\"original: {}, modified: {}\".format(original, modified))" + "print(f\"original: {original}, modified: {modified}\")" ] }, { @@ -144,7 +144,7 @@ "# Alternatively, you can use copy method\n", "# modified = original.copy()\n", "modified[0] = 99\n", - "print(\"original: {}, modified: {}\".format(original, modified))" + "print(f\"original: {original}, modified: {modified}\")" ] }, { @@ -204,14 +204,14 @@ "source": [ "numbers = [8, 1, 6, 5, 10]\n", "numbers.sort()\n", - "print(\"numbers: {}\".format(numbers))\n", + "print(f\"numbers: {numbers}\")\n", "\n", "numbers.sort(reverse=True)\n", - "print(\"numbers reversed: {}\".format(numbers))\n", + "print(f\"numbers reversed: {numbers}\")\n", "\n", "words = [\"this\", \"is\", \"a\", \"list\", \"of\", \"words\"]\n", "words.sort()\n", - "print(\"words: {}\".format(words))" + "print(f\"words: {words}\")" ] }, { @@ -230,7 +230,7 @@ "source": [ "numbers = [8, 1, 6, 5, 10]\n", "sorted_numbers = sorted(numbers)\n", - "print(\"numbers: {}, sorted: {}\".format(numbers, sorted_numbers))" + "print(f\"{numbers=}, {sorted_numbers=}\")" ] }, { @@ -249,7 +249,7 @@ "first_list = [\"beef\", \"ham\"]\n", "second_list = [\"potatoes\", 1, 3]\n", "first_list.extend(second_list)\n", - "print(\"first: {}, second: {}\".format(first_list, second_list))" + "print(f\"{first_list=}, {second_list=}\")" ] }, { @@ -268,11 +268,7 @@ "first = [1, 2, 3]\n", "second = [4, 5]\n", "first += second # same as: first = first + second\n", - "print(\"first: {}\".format(first))\n", - "\n", - "# If you need a new list\n", - "summed = first + second\n", - "print(\"summed: {}\".format(summed))" + "print(f\"{first=}\")" ] }, { @@ -296,7 +292,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -310,7 +306,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/05_dictionaries.ipynb b/notebooks/beginner/notebooks/05_dictionaries.ipynb index 97aa70c..e880cb6 100644 --- a/notebooks/beginner/notebooks/05_dictionaries.ipynb +++ b/notebooks/beginner/notebooks/05_dictionaries.ipynb @@ -15,7 +15,7 @@ "outputs": [], "source": [ "my_empty_dict = {} # alternative: my_empty_dict = dict()\n", - "print(\"dict: {}, type: {}\".format(my_empty_dict, type(my_empty_dict)))" + "print(f\"dict: {my_empty_dict}, type: {type(my_empty_dict)}\")" ] }, { @@ -37,8 +37,8 @@ "print(dict1)\n", "print(dict2)\n", "\n", - "print(\"equal: {}\".format(dict1 == dict2))\n", - "print(\"length: {}\".format(len(dict1)))" + "print(f\"equals: {dict1 == dict2}\")\n", + "print(f\"length: {len(dict1)}\")" ] }, { @@ -54,9 +54,9 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"keys: {}\".format(dict1.keys()))\n", - "print(\"values: {}\".format(dict1.values()))\n", - "print(\"items: {}\".format(dict1.items()))" + "print(f\"keys: {dict1.keys()}\")\n", + "print(f\"values: {dict1.values()}\")\n", + "print(f\"items: {dict1.items()}\")" ] }, { @@ -77,7 +77,7 @@ "my_dict[\"key2\"] = 99\n", "my_dict[\"key1\"] = \"new value\" # overriding existing value\n", "print(my_dict)\n", - "print(\"value of key1: {}\".format(my_dict[\"key1\"]))" + "print(f\"value of key1: {my_dict['key1']}\")" ] }, { @@ -118,7 +118,7 @@ "if key_to_delete in my_dict:\n", " del my_dict[key_to_delete]\n", "else:\n", - " print(\"{key} is not in {dictionary}\".format(key=key_to_delete, dictionary=my_dict))" + " print(f\"{key_to_delete} is not in {my_dict}\")" ] }, { @@ -138,8 +138,8 @@ "my_other_dict = my_dict\n", "my_other_dict[\"carrot\"] = \"super tasty\"\n", "my_other_dict[\"sausage\"] = \"best ever\"\n", - "print(\"my_dict: {}\\nother: {}\".format(my_dict, my_other_dict))\n", - "print(\"equal: {}\".format(my_dict == my_other_dict))" + "print(f\"{my_dict=}\\nother: {my_other_dict}\")\n", + "print(f\"equals: {my_dict == my_other_dict}\")" ] }, { @@ -158,8 +158,8 @@ "my_dict = {\"ham\": \"good\", \"carrot\": \"semi good\"}\n", "my_other_dict = dict(my_dict)\n", "my_other_dict[\"beer\"] = \"decent\"\n", - "print(\"my_dict: {}\\nother: {}\".format(my_dict, my_other_dict))\n", - "print(\"equal: {}\".format(my_dict == my_other_dict))" + "print(f\"{my_dict=}\\nother: {my_other_dict}\")\n", + "print(f\"equals: {my_dict == my_other_dict}\")" ] }, { @@ -178,11 +178,11 @@ "outputs": [], "source": [ "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}\n", - "d = my_dict.get(\"d\")\n", - "print(\"d: {}\".format(d))\n", + "value_of_d = my_dict.get(\"d\")\n", + "print(f\"d: {d}\")\n", "\n", "d = my_dict.get(\"d\", \"my default value\")\n", - "print(\"d: {}\".format(d))" + "print(f\"d: {d}\")" ] }, { @@ -199,15 +199,15 @@ "outputs": [], "source": [ "my_dict = dict(food=\"ham\", drink=\"beer\", sport=\"football\")\n", - "print(\"dict before pops: {}\".format(my_dict))\n", + "print(f\"dict before pops: {my_dict}\")\n", "\n", "food = my_dict.pop(\"food\")\n", - "print(\"food: {}\".format(food))\n", - "print(\"dict after popping food: {}\".format(my_dict))\n", + "print(f\"food: {food}\")\n", + "print(f\"dict after popping food: {my_dict}\")\n", "\n", "food_again = my_dict.pop(\"food\", \"default value for food\")\n", - "print(\"food again: {}\".format(food_again))\n", - "print(\"dict after popping food again: {}\".format(my_dict))" + "print(f\"food again: {food_again}\")\n", + "print(f\"dict after popping food again: {my_dict}\")" ] }, { @@ -227,7 +227,7 @@ "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}\n", "a = my_dict.setdefault(\"a\", \"my default value\")\n", "d = my_dict.setdefault(\"d\", \"my default value\")\n", - "print(\"a: {}\\nd: {}\\nmy_dict: {}\".format(a, d, my_dict))" + "print(f\"a: {a}\\nd: {d}\\nmy_dict: {my_dict}\")" ] }, { @@ -298,7 +298,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -312,7 +312,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/06_for_loops.ipynb b/notebooks/beginner/notebooks/06_for_loops.ipynb index eded387..91c7479 100644 --- a/notebooks/beginner/notebooks/06_for_loops.ipynb +++ b/notebooks/beginner/notebooks/06_for_loops.ipynb @@ -80,7 +80,7 @@ "outputs": [], "source": [ "for idx, val in enumerate(my_list):\n", - " print(\"idx: {}, value: {}\".format(idx, val))" + " print(f\"idx: {idx}, value: {val}\")" ] }, { @@ -108,7 +108,7 @@ "outputs": [], "source": [ "for key, val in my_dict.items():\n", - " print(\"{}={}\".format(key, val))" + " print(f\"{key}={val}\")" ] }, { diff --git a/notebooks/beginner/notebooks/07_functions.ipynb b/notebooks/beginner/notebooks/07_functions.ipynb index bd4957c..d1379a4 100644 --- a/notebooks/beginner/notebooks/07_functions.ipynb +++ b/notebooks/beginner/notebooks/07_functions.ipynb @@ -17,7 +17,7 @@ " print(\"Hello world!\")\n", "\n", "\n", - "print(\"type: {}\".format(my_first_function))\n", + "print(f\"type: {my_first_function}\")\n", "\n", "my_first_function() # Calling a function" ] @@ -36,7 +36,7 @@ "outputs": [], "source": [ "def greet_us(name1, name2):\n", - " print(\"Hello {} and {}!\".format(name1, name2))\n", + " print(f\"Hello {name1} and {name2}!\")\n", "\n", "\n", "greet_us(\"John Doe\", \"Superman\")" @@ -56,7 +56,7 @@ "\n", "uggly_string = \" MixED CaSe \"\n", "pretty = strip_and_lowercase(uggly_string)\n", - "print(\"pretty: {}\".format(pretty))" + "print(f\"pretty: {pretty}\")" ] }, { @@ -186,7 +186,7 @@ "source": [ "def print_sum(val1, val2):\n", " \"\"\"Function which prints the sum of given arguments.\"\"\"\n", - " print(\"sum: {}\".format(val1 + val2))\n", + " print(f\"sum: {val1 + val2}\")\n", "\n", "\n", "print(help(print_sum))" diff --git a/notebooks/beginner/notebooks/10_file_io.ipynb b/notebooks/beginner/notebooks/10_file_io.ipynb index e9b4865..b17e54b 100644 --- a/notebooks/beginner/notebooks/10_file_io.ipynb +++ b/notebooks/beginner/notebooks/10_file_io.ipynb @@ -24,15 +24,15 @@ "import os\n", "\n", "current_file = os.path.realpath(\"file_io.ipynb\")\n", - "print(\"current file: {}\".format(current_file))\n", + "print(f\"current file: {current_file}\")\n", "# Note: in .py files you can get the path of current file by __file__\n", "\n", "current_dir = os.path.dirname(current_file)\n", - "print(\"current directory: {}\".format(current_dir))\n", + "print(f\"current directory: {current_dir}\")\n", "# Note: in .py files you can get the dir of current file by os.path.dirname(__file__)\n", "\n", "data_dir = os.path.join(os.path.dirname(current_dir), \"data\")\n", - "print(\"data directory: {}\".format(data_dir))" + "print(f\"data directory: {data_dir}\")" ] }, { @@ -48,9 +48,9 @@ "metadata": {}, "outputs": [], "source": [ - "print(\"exists: {}\".format(os.path.exists(data_dir)))\n", - "print(\"is file: {}\".format(os.path.isfile(data_dir)))\n", - "print(\"is directory: {}\".format(os.path.isdir(data_dir)))" + "print(f\"exists: {os.path.exists(data_dir)}\")\n", + "print(f\"is file: {os.path.isfile(data_dir)}\")\n", + "print(f\"is directory: {os.path.isdir(data_dir)}\")" ] }, { @@ -68,7 +68,7 @@ "source": [ "file_path = os.path.join(data_dir, \"simple_file.txt\")\n", "\n", - "with open(file_path, \"r\") as simple_file:\n", + "with open(file_path) as simple_file:\n", " for line in simple_file:\n", " print(line.strip())" ] @@ -93,7 +93,7 @@ "file_path = os.path.join(data_dir, \"simple_file.txt\")\n", "\n", "# THIS IS NOT THE PREFERRED WAY\n", - "simple_file = open(file_path, \"r\")\n", + "simple_file = open(file_path)\n", "for line in simple_file:\n", " print(line.strip())\n", "simple_file.close() # This has to be called explicitly" diff --git a/notebooks/beginner/notebooks/11_classes.ipynb b/notebooks/beginner/notebooks/11_classes.ipynb index 0eedf2e..c3c8747 100644 --- a/notebooks/beginner/notebooks/11_classes.ipynb +++ b/notebooks/beginner/notebooks/11_classes.ipynb @@ -18,7 +18,7 @@ " self.name = name\n", "\n", " def greet(self):\n", - " print(\"Hello {}!\".format(self.name))" + " print(f\"Hello {self.name}!\")" ] }, { @@ -28,9 +28,9 @@ "outputs": [], "source": [ "my_instance = MyFirstClass(\"John Doe\")\n", - "print(\"my_instance: {}\".format(my_instance))\n", - "print(\"type: {}\".format(type(my_instance)))\n", - "print(\"my_instance.name: {}\".format(my_instance.name))" + "print(f\"my_instance: {my_instance}\")\n", + "print(f\"type: {type(my_instance)}\")\n", + "print(f\"my_instance.name: {my_instance.name}\")" ] }, { @@ -94,7 +94,7 @@ " self.second_var = var2\n", "\n", " def print_variables(self):\n", - " print(\"{} {}\".format(self.first_var, self.second_var))\n", + " print(f\"{self.first_var} {self.second_var}\")\n", "\n", "\n", "e = Example(\"abc\", 123)\n", @@ -121,11 +121,11 @@ " self.age = age\n", "\n", " def __str__(self):\n", - " return \"Person: {}\".format(self.name)\n", + " return f\"Person: {self.name}\"\n", "\n", "\n", "jack = Person(\"Jack\", 82)\n", - "print(\"This is the string presentation of jack: {}\".format(jack))" + "print(f\"This is the string presentation of jack: {jack}\")" ] }, { @@ -251,7 +251,7 @@ "\n", " def celebrate_birthday(self):\n", " self._age += 1\n", - " print(\"Happy bday for {} years old!\".format(self._age))\n", + " print(f\"Happy bday for {self._age} years old!\")\n", "\n", "\n", "example_person = Person(age=15)\n", @@ -299,11 +299,11 @@ "source": [ "dog = Dog()\n", "dog.greet()\n", - "print(\"Dog's favorite food is {}\".format(dog.favorite_food))\n", + "print(f\"Dog's favorite food is {dog.favorite_food}\")\n", "\n", "cat = Cat()\n", "cat.greet()\n", - "print(\"Cat's favorite food is {}\".format(cat.favorite_food))" + "print(f\"Cat's favorite food is {cat.favorite_food}\")" ] } ], diff --git a/notebooks/beginner/notebooks/12_exceptions.ipynb b/notebooks/beginner/notebooks/12_exceptions.ipynb index 94d7268..86d1ea6 100644 --- a/notebooks/beginner/notebooks/12_exceptions.ipynb +++ b/notebooks/beginner/notebooks/12_exceptions.ipynb @@ -37,12 +37,12 @@ "file_name = \"not_existing.txt\"\n", "\n", "try:\n", - " with open(file_name, \"r\") as my_file:\n", + " with open(file_name) as my_file:\n", " print(\"File is successfully open\")\n", "\n", "except FileNotFoundError as e:\n", - " print(\"Uups, file: {} not found\".format(file_name))\n", - " print(\"Exception: {} was raised\".format(e))" + " print(f\"Uups, file: {file_name} not found\")\n", + " print(f\"Exception: {e} was raised\")" ] }, { @@ -66,19 +66,19 @@ " except ZeroDivisionError as ex1:\n", " print(\"Can't divide by zero\")\n", " except Exception as ex2:\n", - " print(\"Exception: {}\".format(ex2))\n", + " print(f\"Exception: {ex2}\")\n", "\n", " return result\n", "\n", "\n", "result1 = calculate_division(3, 3)\n", - "print(\"result1: {}\".format(result1))\n", + "print(f\"result1: {result1}\")\n", "\n", "result2 = calculate_division(3, \"3\")\n", - "print(\"result2: {}\".format(result2))\n", + "print(f\"result2: {result2}\")\n", "\n", "result3 = calculate_division(3, 0)\n", - "print(\"result3: {}\".format(result3))" + "print(f\"result3: {result3}\")" ] }, { diff --git a/notebooks/beginner/notebooks/14_debugging.ipynb b/notebooks/beginner/notebooks/14_debugging.ipynb index 57acdc4..cf47ac8 100644 --- a/notebooks/beginner/notebooks/14_debugging.ipynb +++ b/notebooks/beginner/notebooks/14_debugging.ipynb @@ -64,16 +64,16 @@ " self._greet_polite(person)\n", "\n", " def _greet_polite(self, name):\n", - " greeting = \"G'day {}! How are you doing?\".format(name)\n", + " greeting = f\"G'day {name}! How are you doing?\"\n", " print(greeting)\n", "\n", " def _greet_street_style(self, name):\n", " # import pdb; pdb.set_trace() # UNCOMMENT\n", " name = name.upper()\n", - " print(\"WASSUP {}!?\".format(name))\n", + " print(f\"WASSUP {name}!?\")\n", "\n", " def _greet_hawaii(self, name):\n", - " print(\"Aloha {}!\".format(name))\n", + " print(f\"Aloha {name}!\")\n", "\n", "\n", "def main():\n", diff --git a/notebooks/beginner/notebooks/15_std_lib.ipynb b/notebooks/beginner/notebooks/15_std_lib.ipynb index 3d13f3b..e2e4b50 100644 --- a/notebooks/beginner/notebooks/15_std_lib.ipynb +++ b/notebooks/beginner/notebooks/15_std_lib.ipynb @@ -24,10 +24,10 @@ "import datetime as dt\n", "\n", "local_now = dt.datetime.now()\n", - "print(\"local now: {}\".format(local_now))\n", + "print(f\"local now: {local_now}\")\n", "\n", "utc_now = dt.datetime.utcnow()\n", - "print(\"utc now: {}\".format(utc_now))\n", + "print(f\"utc now: {utc_now}\")\n", "\n", "# You can access any value separately:\n", "print(\n", @@ -41,8 +41,8 @@ " )\n", ")\n", "\n", - "print(\"date: {}\".format(local_now.date()))\n", - "print(\"time: {}\".format(local_now.time()))" + "print(f\"date: {local_now.date()}\")\n", + "print(f\"time: {local_now.time()}\")" ] }, { @@ -81,7 +81,7 @@ "outputs": [], "source": [ "my_dt = dt.datetime.strptime(\"2000-01-01 10:00:00\", \"%Y-%m-%d %H:%M:%S\")\n", - "print(\"my_dt: {}\".format(my_dt))" + "print(f\"my_dt: {my_dt}\")" ] }, { @@ -99,12 +99,12 @@ "outputs": [], "source": [ "tomorrow = local_now + dt.timedelta(days=1)\n", - "print(\"tomorrow this time: {}\".format(tomorrow))\n", + "print(f\"tomorrow this time: {tomorrow}\")\n", "\n", "delta = tomorrow - local_now\n", - "print(\"tomorrow - now = {}\".format(delta))\n", - "print(\"days: {}, seconds: {}\".format(delta.days, delta.seconds))\n", - "print(\"total seconds: {}\".format(delta.total_seconds()))" + "print(f\"tomorrow - now = {delta}\")\n", + "print(f\"days: {delta.days}, seconds: {delta.seconds}\")\n", + "print(f\"total seconds: {delta.total_seconds()}\")" ] }, { @@ -136,21 +136,21 @@ "import pytz\n", "\n", "naive_utc_now = dt.datetime.utcnow()\n", - "print(\"naive utc now: {}, tzinfo: {}\".format(naive_utc_now, naive_utc_now.tzinfo))\n", + "print(f\"naive utc now: {naive_utc_now}, tzinfo: {naive_utc_now.tzinfo}\")\n", "\n", "# Localizing naive datetimes\n", "UTC_TZ = pytz.timezone(\"UTC\")\n", "utc_now = UTC_TZ.localize(naive_utc_now)\n", - "print(\"utc now: {}, tzinfo: {}\".format(utc_now, utc_now.tzinfo))\n", + "print(f\"utc now: {utc_now}, tzinfo: {utc_now.tzinfo}\")\n", "\n", "# Converting localized datetimes to different timezone\n", "PARIS_TZ = pytz.timezone(\"Europe/Paris\")\n", "paris_now = PARIS_TZ.normalize(utc_now)\n", - "print(\"Paris: {}, tzinfo: {}\".format(paris_now, paris_now.tzinfo))\n", + "print(f\"Paris: {paris_now}, tzinfo: {paris_now.tzinfo}\")\n", "\n", "NEW_YORK_TZ = pytz.timezone(\"America/New_York\")\n", "ny_now = NEW_YORK_TZ.normalize(utc_now)\n", - "print(\"New York: {}, tzinfo: {}\".format(ny_now, ny_now.tzinfo))" + "print(f\"New York: {ny_now}, tzinfo: {ny_now.tzinfo}\")" ] }, { @@ -293,10 +293,10 @@ "import random\n", "\n", "rand_int = random.randint(1, 100)\n", - "print(\"random integer between 1-100: {}\".format(rand_int))\n", + "print(f\"random integer between 1-100: {rand_int}\")\n", "\n", "rand = random.random()\n", - "print(\"random float between 0-1: {}\".format(rand))" + "print(f\"random float between 0-1: {rand}\")" ] }, { @@ -348,12 +348,12 @@ "search_pattern = r\"(g12)\"\n", "\n", "match = re.search(search_pattern, secret_code)\n", - "print(\"match: {}\".format(match))\n", - "print(\"match.group(): {}\".format(match.group()))\n", + "print(f\"match: {match}\")\n", + "print(f\"match.group(): {match.group()}\")\n", "\n", "numbers_pattern = r\"[0-9]\"\n", "numbers_match = re.findall(numbers_pattern, secret_code)\n", - "print(\"numbers: {}\".format(numbers_match))" + "print(f\"numbers: {numbers_match}\")" ] }, { diff --git a/notebooks/beginner/notebooks/16_testing2.ipynb b/notebooks/beginner/notebooks/16_testing2.ipynb index 06b013f..7549d19 100644 --- a/notebooks/beginner/notebooks/16_testing2.ipynb +++ b/notebooks/beginner/notebooks/16_testing2.ipynb @@ -48,7 +48,7 @@ "\n", " @property\n", " def full_name(self):\n", - " return \"{} {}\".format(self.first_name, self.last_name)\n", + " return f\"{self.first_name} {self.last_name}\"\n", "\n", " @property\n", " def as_dict(self):\n", diff --git a/notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb b/notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb index 072d73a..c61bbb4 100644 --- a/notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb +++ b/notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb @@ -22,7 +22,7 @@ "\n", "\n", "def get_wiki_article(name):\n", - " url = \"https://en.wikipedia.org/wiki/%7B%7D/".format(name)\n", + " url = f\"https://en.wikipedia.org/wiki/%7Bname%7D/"\n", " response = urlopen(url)\n", " content = str(response.read())\n", " return content" diff --git a/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb b/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb index e1776c3..bfae2e0 100644 --- a/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb +++ b/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb @@ -84,7 +84,7 @@ " 2. numeric values (list of floats)\n", " 3. non-numeric values (list of strings)\n", " \"\"\"\n", - " data_file = open(path, \"r\")\n", + " data_file = open(path)\n", " lines = data_file.readlines()\n", " line_count = len(lines)\n", " idx = 0\n", diff --git a/notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb b/notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb index 4b3f446..73c1b1a 100644 --- a/notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb +++ b/notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb @@ -90,7 +90,7 @@ "outputs": [], "source": [ "for idx, val in enumerate(data):\n", - " print(\"{}: {}\".format(idx, val))" + " print(f\"{idx}: {val}\")" ] }, { diff --git a/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb index fcc27e6..f1fdc2f 100644 --- a/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb +++ b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb @@ -220,7 +220,7 @@ "outputs": [], "source": [ "def word_count_of_txt_file(file_path):\n", - " with open(file_path, \"r\") as f:\n", + " with open(file_path) as f:\n", " content = f.read()\n", " return len(content.split())" ] diff --git a/notebooks/intermediate/notebooks/01_std_lib2.ipynb b/notebooks/intermediate/notebooks/01_std_lib2.ipynb index b567924..2c0c84f 100644 --- a/notebooks/intermediate/notebooks/01_std_lib2.ipynb +++ b/notebooks/intermediate/notebooks/01_std_lib2.ipynb @@ -40,7 +40,7 @@ "import json\n", "\n", "json_data = json.dumps(data)\n", - "print(\"type: {} data: {}\".format(type(json_data), json_data))" + "print(f\"type: {type(json_data)} data: {json_data}\")" ] }, { @@ -57,7 +57,7 @@ "outputs": [], "source": [ "decoded = json.loads(json_data)\n", - "print(\"type: {} data: {}\".format(type(decoded), decoded))" + "print(f\"type: {type(decoded)} data: {decoded}\")" ] }, { @@ -217,7 +217,7 @@ "lisa = Person(\"Lis Doe\", age=77, is_gangster=False)\n", "\n", "print(john, lisa)\n", - "print(\"Is John a gangster: {}\".format(john.is_gangster))\n", + "print(f\"Is John a gangster: {john.is_gangster}\")\n", "\n", "# tuples are immutable, thus you can't do this\n", "# john.is_gangster = False" @@ -242,12 +242,12 @@ "data = [1, 2, 3, 1, 2, 4, 5, 6, 2]\n", "\n", "counter = Counter(data)\n", - "print(\"type: {}, counter: {}\".format(type(counter), counter))\n", + "print(f\"type: {type(counter)}, counter: {counter}\")\n", "\n", - "print(\"count of twos: {}\".format(counter[2]))\n", - "print(\"count of tens: {}\".format(counter[10])) # zero for non existing\n", + "print(f\"count of twos: {counter[2]}\")\n", + "print(f\"count of tens: {counter[10]}\") # zero for non existing\n", "\n", - "print(\"counter is a dict: {}\".format(isinstance(counter, dict)))" + "print(f\"counter is a dict: {isinstance(counter, dict)}\")" ] }, { diff --git a/notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb b/notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb index 0cccc10..4303755 100644 --- a/notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb +++ b/notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb @@ -295,7 +295,7 @@ "source": [ "for key in my_dict:\n", " val = my_dict[key]\n", - " print(\"key: {:15s} value: {}\".format(key, val))" + " print(f\"key: {key:15s} value: {val}\")" ] }, { @@ -312,7 +312,7 @@ "outputs": [], "source": [ "for key, val in my_dict.items():\n", - " print(\"key: {:15s} value: {}\".format(key, val))" + " print(f\"key: {key:15s} value: {val}\")" ] } ], diff --git a/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb b/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb index 8b9c642..ad6c8d1 100644 --- a/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb +++ b/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb @@ -328,7 +328,7 @@ " all_values_truthy = False\n", " break\n", "\n", - "print(\"any truthy: {}, all truthy: {}\".format(any_value_truthy, all_values_truthy))" + "print(f\"any truthy: {any_value_truthy}, all truthy: {all_values_truthy}\")" ] }, { @@ -346,7 +346,7 @@ "source": [ "any_value_truthy = any(example_collection)\n", "all_values_truthy = all(example_collection)\n", - "print(\"any truthy: {}, all truthy: {}\".format(any_value_truthy, all_values_truthy))" + "print(f\"any truthy: {any_value_truthy}, all truthy: {all_values_truthy}\")" ] }, { diff --git a/notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb b/notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb index 7500f1b..d709c07 100644 --- a/notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb +++ b/notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb @@ -149,10 +149,10 @@ " bad_calculation = 1 / 0\n", "\n", "except ValueError as e:\n", - " print(\"Oh boi, some value error: {}\".format(e))\n", + " print(f\"Oh boi, some value error: {e}\")\n", " exception_occured = True\n", "except Exception as e:\n", - " print(\"Oh boi, something bad happened: {}\".format(e))\n", + " print(f\"Oh boi, something bad happened: {e}\")\n", " exception_occured = True\n", "\n", "if not exception_occured:\n", @@ -178,9 +178,9 @@ " bad_calculation = 1 / 0\n", "\n", "except ValueError as e:\n", - " print(\"Oh boi, some keyerror: {}\".format(e))\n", + " print(f\"Oh boi, some keyerror: {e}\")\n", "except Exception as e:\n", - " print(\"Oh boi, something bad happened: {}\".format(e))\n", + " print(f\"Oh boi, something bad happened: {e}\")\n", "else:\n", " print(\"All went well!\")" ] @@ -221,7 +221,7 @@ " return result\n", "\n", "\n", - "print(\"return value: {}\".format(magical_calculation()))" + "print(f\"return value: {magical_calculation()}\")" ] }, { @@ -250,7 +250,7 @@ " return result\n", "\n", "\n", - "print(\"return value: {}\".format(magical_calculation()))" + "print(f\"return value: {magical_calculation()}\")" ] }, { @@ -283,13 +283,13 @@ "source": [ "try:\n", " some_file = open(\"tmp.txt\", \"w\")\n", - " print(\"the file is now open: {}\".format(not some_file.closed))\n", + " print(f\"the file is now open: {not some_file.closed}\")\n", "\n", " # here would be some logic\n", "\n", "finally:\n", " some_file.close()\n", - " print(\"now it's closed: {}\".format(some_file.closed))" + " print(f\"now it's closed: {some_file.closed}\")" ] }, { @@ -306,11 +306,11 @@ "outputs": [], "source": [ "with open(\"tmp.txt\", \"w\") as some_file:\n", - " print(\"the file is now open: {}\".format(not some_file.closed))\n", + " print(f\"the file is now open: {not some_file.closed}\")\n", "\n", " # here would be some logic\n", "\n", - "print(\"now it's closed: {}\".format(some_file.closed))" + "print(f\"now it's closed: {some_file.closed}\")" ] }, { @@ -476,7 +476,7 @@ " self.last_name = last_name\n", "\n", " def get_full_name(self):\n", - " return \"{} {}\".format(self.first_name, self.last_name)\n", + " return f\"{self.first_name} {self.last_name}\"\n", "\n", " def set_full_name(self, full_name):\n", " parts = full_name.split()\n", @@ -512,7 +512,7 @@ "\n", " @property\n", " def full_name(self):\n", - " return \"{} {}\".format(self.first_name, self.last_name)\n", + " return f\"{self.first_name} {self.last_name}\"\n", "\n", " @full_name.setter\n", " def full_name(self, name):\n", From 02436df8234f4a1d7fb4d154d52c765679739beb Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Fri, 21 Apr 2023 13:47:20 +0300 Subject: [PATCH 17/30] Update readme --- README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8c8ecd3..fac79a2 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,13 @@ # Learn Python 3 -[![Build Status](https://travis-ci.org/jerry-git/learn-python3.svg?branch=master)](https://travis-ci.org/jerry-git/learn-python3) - ## Introduction -This repository contains a collection of materials for teaching/learning Python 3 (3.5+). +This repository contains a collection of materials for teaching/learning Python 3 (3.10+). #### Requirements -* Have Python 3.5 or newer installed. You can check the version by typing `python3 --version` in your command line. You can download the latest Python version from [here](https://www.python.org/downloads/). -* Have [Jupyter Notebook installed](http://jupyter.readthedocs.io/en/latest/install.html). +* Have Python 3.10 or newer installed. You can check the version by typing `python3 --version` in your command line. You can download the latest Python version from [here](https://www.python.org/downloads/). +* Have [Jupyter Notebook installed](http://jupyter.readthedocs.io/en/latest/install.html). `pip install jupyter` is sufficient in most cases. If you can not access Python and/or Jupyter Notebook on your machine, you can still follow the web based materials. However, you should be able to use Jupyter Notebook in order to complete the exercises. From 4bc0a781f6da53105dc49d1c6ed894da82775737 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Fri, 21 Apr 2023 14:14:52 +0300 Subject: [PATCH 18/30] Fix undefined variable --- notebooks/beginner/notebooks/05_dictionaries.ipynb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/notebooks/beginner/notebooks/05_dictionaries.ipynb b/notebooks/beginner/notebooks/05_dictionaries.ipynb index e880cb6..152ee95 100644 --- a/notebooks/beginner/notebooks/05_dictionaries.ipynb +++ b/notebooks/beginner/notebooks/05_dictionaries.ipynb @@ -179,10 +179,10 @@ "source": [ "my_dict = {\"a\": 1, \"b\": 2, \"c\": 3}\n", "value_of_d = my_dict.get(\"d\")\n", - "print(f\"d: {d}\")\n", + "print(f\"d: {value_of_d}\")\n", "\n", - "d = my_dict.get(\"d\", \"my default value\")\n", - "print(f\"d: {d}\")" + "value_of_d = my_dict.get(\"d\", \"my default value\")\n", + "print(f\"d: {value_of_d}\")" ] }, { From 1409ba8bb41c59dcee87e8741185960aaf67073f Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Fri, 21 Apr 2023 14:15:08 +0300 Subject: [PATCH 19/30] Minor fixes --- notebooks/beginner/notebooks/07_functions.ipynb | 6 +++--- notebooks/beginner/notebooks/10_file_io.ipynb | 4 ++-- notebooks/beginner/notebooks/11_classes.ipynb | 6 ++---- notebooks/beginner/notebooks/12_exceptions.ipynb | 8 ++++---- .../beginner/notebooks/13_modules_and_packages.ipynb | 10 +++++----- 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/notebooks/beginner/notebooks/07_functions.ipynb b/notebooks/beginner/notebooks/07_functions.ipynb index d1379a4..f6a6ded 100644 --- a/notebooks/beginner/notebooks/07_functions.ipynb +++ b/notebooks/beginner/notebooks/07_functions.ipynb @@ -17,7 +17,7 @@ " print(\"Hello world!\")\n", "\n", "\n", - "print(f\"type: {my_first_function}\")\n", + "print(f\"type: {type(my_first_function)}\")\n", "\n", "my_first_function() # Calling a function" ] @@ -240,7 +240,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -254,7 +254,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/10_file_io.ipynb b/notebooks/beginner/notebooks/10_file_io.ipynb index b17e54b..992136c 100644 --- a/notebooks/beginner/notebooks/10_file_io.ipynb +++ b/notebooks/beginner/notebooks/10_file_io.ipynb @@ -138,7 +138,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -152,7 +152,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/11_classes.ipynb b/notebooks/beginner/notebooks/11_classes.ipynb index c3c8747..81e50e9 100644 --- a/notebooks/beginner/notebooks/11_classes.ipynb +++ b/notebooks/beginner/notebooks/11_classes.ipynb @@ -152,9 +152,7 @@ " self.instance_variable = var1\n", "\n", " def show_info(self):\n", - " info = \"instance_variable: {}, name: {}, description: {}\".format(\n", - " self.instance_variable, Example.name, Example.description\n", - " )\n", + " info = f\"instance_variable: {self.instance_variable}, name: {Example.name}, description: {Example.description}\"\n", " print(info)\n", "\n", "\n", @@ -323,7 +321,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/12_exceptions.ipynb b/notebooks/beginner/notebooks/12_exceptions.ipynb index 86d1ea6..a50fc25 100644 --- a/notebooks/beginner/notebooks/12_exceptions.ipynb +++ b/notebooks/beginner/notebooks/12_exceptions.ipynb @@ -144,23 +144,23 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", - "version": 3.0 + "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, - "nbformat_minor": 0 + "nbformat_minor": 1 } diff --git a/notebooks/beginner/notebooks/13_modules_and_packages.ipynb b/notebooks/beginner/notebooks/13_modules_and_packages.ipynb index 00833fd..fd2e680 100644 --- a/notebooks/beginner/notebooks/13_modules_and_packages.ipynb +++ b/notebooks/beginner/notebooks/13_modules_and_packages.ipynb @@ -62,13 +62,13 @@ "```python\n", "\n", "def get_available_brands():\n", - " return ['chiquita']\n", + " return [\"chiquita\"]\n", "\n", "\n", "class Banana:\n", - " def __init__(self, brand='chiquita'):\n", + " def __init__(self, brand=\"chiquita\"):\n", " if brand not in get_available_brands():\n", - " raise ValueError('Unkown brand: {}'.format(brand))\n", + " raise ValueError(f\"Unknown brand: {brand}\")\n", " self._brand = brand\n", " \n", "```" @@ -112,7 +112,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -126,7 +126,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, From 5f305d7bcb19c3da11fbb48a81e6b36304c112be Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Sat, 22 Apr 2023 14:54:46 +0300 Subject: [PATCH 20/30] Use pathlib --- .../exercises/10_file_io_exercise.ipynb | 25 +++++------ .../exercises/19_recap2_exercise.ipynb | 14 +++--- notebooks/beginner/notebooks/10_file_io.ipynb | 27 ++++++------ notebooks/beginner/notebooks/15_std_lib.ipynb | 43 ++++++------------- .../05_idiomatic_python_exercise.ipynb | 18 ++++---- 5 files changed, 55 insertions(+), 72 deletions(-) diff --git a/notebooks/beginner/exercises/10_file_io_exercise.ipynb b/notebooks/beginner/exercises/10_file_io_exercise.ipynb index 2fcb284..bfeaec4 100644 --- a/notebooks/beginner/exercises/10_file_io_exercise.ipynb +++ b/notebooks/beginner/exercises/10_file_io_exercise.ipynb @@ -10,11 +10,11 @@ "source": [ "# EXECUTE THIS ONE FIRST!\n", "\n", - "import os\n", + "from pathlib import Path\n", "\n", "# Constants for the exercises:\n", - "WORKING_DIR = os.getcwd()\n", - "DATA_DIR = os.path.join(os.path.dirname(WORKING_DIR), \"data\")" + "WORKING_DIR = Path.cwd()\n", + "DATA_DIR = WORKING_DIR.parent / \"data\"" ] }, { @@ -32,12 +32,12 @@ "outputs": [], "source": [ "def sum_numbers_in_file(input_file):\n", - " sum_ = 0 # A common way to use variable names that collide with built-in/keyword words is to add underscore\n", - " with ____(input_file, ____) as ____:\n", + " total = 0\n", + " with ____(input_file) as ____:\n", " for line in ____:\n", " ____ = line.strip() # Remove potential white space\n", - " ____ += float(____)\n", - " return ____" + " total += float(____)\n", + " return _____" ] }, { @@ -48,7 +48,7 @@ }, "outputs": [], "source": [ - "in_file = os.path.join(DATA_DIR, \"numbers.txt\")\n", + "in_file = DATA_DIR / \"numbers.txt\"\n", "assert sum_numbers_in_file(in_file) == 189.5" ] }, @@ -77,8 +77,8 @@ }, "outputs": [], "source": [ - "in_file1 = os.path.join(DATA_DIR, \"simple_file.txt\")\n", - "in_file2 = os.path.join(DATA_DIR, \"simple_file_with_empty_lines.txt\")\n", + "in_file1 = DATA_DIR / \"simple_file.txt\"\n", + "in_file2 = DATA_DIR / \"simple_file_with_empty_lines.txt\"\n", "\n", "expected_file_1 = [\"First\", \"Second\", \"Third\", \"And\"]\n", "assert find_first_words(in_file1) == expected_file_1\n", @@ -89,8 +89,9 @@ } ], "metadata": { + "celltoolbar": "Edit Metadata", "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -104,7 +105,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/exercises/19_recap2_exercise.ipynb b/notebooks/beginner/exercises/19_recap2_exercise.ipynb index e5811e5..41c76b9 100644 --- a/notebooks/beginner/exercises/19_recap2_exercise.ipynb +++ b/notebooks/beginner/exercises/19_recap2_exercise.ipynb @@ -128,11 +128,11 @@ }, "outputs": [], "source": [ - "import os\n", + "from pathlib import Path\n", "\n", - "WORKING_DIR = os.getcwd()\n", - "DATA_DIR = os.path.join(os.path.dirname(WORKING_DIR), \"data\")\n", - "DATA_FILE = os.path.join(DATA_DIR, \"random_data.txt\")\n", + "WORKING_DIR = Path.cwd()\n", + "DATA_DIR = WORKING_DIR.parent / \"data\"\n", + "DATA_FILE = DATA_DIR / \"random_data.txt\"\n", "\n", "da = DataAnalyzer(DATA_FILE)\n", "\n", @@ -171,7 +171,7 @@ }, "outputs": [], "source": [ - "EMPTY_FILE = os.path.join(DATA_DIR, \"empty_file.txt\")\n", + "EMPTY_FILE = DATA_DIR / \"empty_file.txt\"\n", "try:\n", " da_empty = DataAnalyzer(EMPTY_FILE)\n", "except NoData:\n", @@ -183,7 +183,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -197,7 +197,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/10_file_io.ipynb b/notebooks/beginner/notebooks/10_file_io.ipynb index 992136c..5cfb788 100644 --- a/notebooks/beginner/notebooks/10_file_io.ipynb +++ b/notebooks/beginner/notebooks/10_file_io.ipynb @@ -21,17 +21,16 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", + "from pathlib import Path\n", "\n", - "current_file = os.path.realpath(\"file_io.ipynb\")\n", + "current_file = Path(\"file_io.ipynb\").resolve()\n", "print(f\"current file: {current_file}\")\n", - "# Note: in .py files you can get the path of current file by __file__\n", + "# Note: in .py files you can get the path of current file by Path(__file__)\n", "\n", - "current_dir = os.path.dirname(current_file)\n", + "current_dir = current_file.parent\n", "print(f\"current directory: {current_dir}\")\n", - "# Note: in .py files you can get the dir of current file by os.path.dirname(__file__)\n", "\n", - "data_dir = os.path.join(os.path.dirname(current_dir), \"data\")\n", + "data_dir = current_dir.parent / \"data\"\n", "print(f\"data directory: {data_dir}\")" ] }, @@ -48,9 +47,9 @@ "metadata": {}, "outputs": [], "source": [ - "print(f\"exists: {os.path.exists(data_dir)}\")\n", - "print(f\"is file: {os.path.isfile(data_dir)}\")\n", - "print(f\"is directory: {os.path.isdir(data_dir)}\")" + "print(f\"exists: {data_dir.exists()}\")\n", + "print(f\"is file: {data_dir.is_file()}\")\n", + "print(f\"is directory: {data_dir.is_dir()}\")" ] }, { @@ -66,7 +65,7 @@ "metadata": {}, "outputs": [], "source": [ - "file_path = os.path.join(data_dir, \"simple_file.txt\")\n", + "file_path = data_dir / \"simple_file.txt\"\n", "\n", "with open(file_path) as simple_file:\n", " for line in simple_file:\n", @@ -90,7 +89,7 @@ "metadata": {}, "outputs": [], "source": [ - "file_path = os.path.join(data_dir, \"simple_file.txt\")\n", + "file_path = data_dir / \"simple_file.txt\"\n", "\n", "# THIS IS NOT THE PREFERRED WAY\n", "simple_file = open(file_path)\n", @@ -112,7 +111,7 @@ "metadata": {}, "outputs": [], "source": [ - "new_file_path = os.path.join(data_dir, \"new_file.txt\")\n", + "new_file_path = data_dir / \"new_file.txt\"\n", "\n", "with open(new_file_path, \"w\") as my_file:\n", " my_file.write(\"This is my first file that I wrote with Python.\")" @@ -131,8 +130,8 @@ "metadata": {}, "outputs": [], "source": [ - "if os.path.exists(new_file_path): # make sure it's there\n", - " os.remove(new_file_path)" + "if new_file_path.exists(): # make sure it's there\n", + " new_file_path.unlink()" ] } ], diff --git a/notebooks/beginner/notebooks/15_std_lib.ipynb b/notebooks/beginner/notebooks/15_std_lib.ipynb index e2e4b50..085156f 100644 --- a/notebooks/beginner/notebooks/15_std_lib.ipynb +++ b/notebooks/beginner/notebooks/15_std_lib.ipynb @@ -31,14 +31,7 @@ "\n", "# You can access any value separately:\n", "print(\n", - " \"{} {} {} {} {} {}\".format(\n", - " local_now.year,\n", - " local_now.month,\n", - " local_now.day,\n", - " local_now.hour,\n", - " local_now.minute,\n", - " local_now.second,\n", - " )\n", + " f\"{local_now.year} {local_now.month} {local_now.day} {local_now.hour} {local_now.minute} {local_now.second}\"\n", ")\n", "\n", "print(f\"date: {local_now.date()}\")\n", @@ -111,19 +104,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### Working with timezones\n", - "Let's first make sure [`pytz`](http://pytz.sourceforge.net/) is installed." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import sys\n", - "\n", - "!{sys.executable} -m pip install pytz" + "### Working with timezones" ] }, { @@ -133,23 +114,23 @@ "outputs": [], "source": [ "import datetime as dt\n", - "import pytz\n", + "from zoneinfo import ZoneInfo\n", "\n", "naive_utc_now = dt.datetime.utcnow()\n", "print(f\"naive utc now: {naive_utc_now}, tzinfo: {naive_utc_now.tzinfo}\")\n", "\n", "# Localizing naive datetimes\n", - "UTC_TZ = pytz.timezone(\"UTC\")\n", - "utc_now = UTC_TZ.localize(naive_utc_now)\n", + "UTC_TZ = ZoneInfo(\"UTC\")\n", + "utc_now = naive_utc_now.replace(tzinfo=UTC_TZ)\n", "print(f\"utc now: {utc_now}, tzinfo: {utc_now.tzinfo}\")\n", "\n", "# Converting localized datetimes to different timezone\n", - "PARIS_TZ = pytz.timezone(\"Europe/Paris\")\n", - "paris_now = PARIS_TZ.normalize(utc_now)\n", + "PARIS_TZ = ZoneInfo(\"Europe/Paris\")\n", + "paris_now = utc_now.astimezone(PARIS_TZ)\n", "print(f\"Paris: {paris_now}, tzinfo: {paris_now.tzinfo}\")\n", "\n", - "NEW_YORK_TZ = pytz.timezone(\"America/New_York\")\n", - "ny_now = NEW_YORK_TZ.normalize(utc_now)\n", + "NEW_YORK_TZ = ZoneInfo(\"America/New_York\")\n", + "ny_now = utc_now.astimezone(NEW_YORK_TZ)\n", "print(f\"New York: {ny_now}, tzinfo: {ny_now.tzinfo}\")" ] }, @@ -248,8 +229,8 @@ "metadata": {}, "outputs": [], "source": [ - "import os\n", "import logging\n", + "from pathlib import Path\n", "\n", "# This is only required for Jupyter notebook environment\n", "from importlib import reload\n", @@ -259,7 +240,7 @@ "logger = logging.getLogger(\"MyFileLogger\")\n", "\n", "# Let's define a file_handler for our logger\n", - "log_path = os.path.join(os.getcwd(), \"my_log.txt\")\n", + "log_path = Path.cwd() / \"my_log.txt\"\n", "file_handler = logging.FileHandler(log_path)\n", "\n", "# And a nice format\n", @@ -401,7 +382,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb b/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb index bfae2e0..276873f 100644 --- a/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb +++ b/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb @@ -260,14 +260,15 @@ }, "outputs": [], "source": [ - "import os\n", + "from pathlib import Path\n", "\n", - "CURRENT_DIR = os.getcwd()\n", - "DATA_DIR = os.path.join(os.path.dirname(CURRENT_DIR), \"data\")\n", + "CURRENT_DIR = Path.cwd()\n", + "DATA_DIR = CURRENT_DIR.parent / \"data\"\n", + "\n", + "DATA_FILE1 = DATA_DIR / \"misc_data1.txt\"\n", + "DATA_FILE2 = DATA_DIR / \"misc_data2.txt\"\n", + "DATA_FILE3 = DATA_DIR / \"empty.txt\"\n", "\n", - "DATA_FILE1 = os.path.join(DATA_DIR, \"misc_data1.txt\")\n", - "DATA_FILE2 = os.path.join(DATA_DIR, \"misc_data2.txt\")\n", - "DATA_FILE3 = os.path.join(DATA_DIR, \"empty.txt\")\n", "\n", "expected1 = \"\"\"missing values: 2\n", "highest number: 99.0\n", @@ -317,8 +318,9 @@ } ], "metadata": { + "celltoolbar": "Edit Metadata", "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -332,7 +334,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, From 3e497ee5e3eea5fddc5d78956976c0232548c8cf Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Sat, 22 Apr 2023 14:55:09 +0300 Subject: [PATCH 21/30] Use ipython friendly debugging --- .../exercises/14_debugging_exercise.ipynb | 3 ++- notebooks/beginner/notebooks/14_debugging.ipynb | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/notebooks/beginner/exercises/14_debugging_exercise.ipynb b/notebooks/beginner/exercises/14_debugging_exercise.ipynb index 6bfbf4e..8577ddc 100644 --- a/notebooks/beginner/exercises/14_debugging_exercise.ipynb +++ b/notebooks/beginner/exercises/14_debugging_exercise.ipynb @@ -18,6 +18,7 @@ "source": [ "def stripped_reversed_lowercase(original):\n", " # Set a breakpoint here and start debugging\n", + " # from IPython.core.debugger import Pdb; Pdb().set_trace()\n", " stripped = original.lstrip()\n", " reversed = \" \".join(reversed(stripped))\n", " reversed.lower()\n", @@ -55,7 +56,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.3" + "version": "3.11.0" } }, "nbformat": 4, diff --git a/notebooks/beginner/notebooks/14_debugging.ipynb b/notebooks/beginner/notebooks/14_debugging.ipynb index cf47ac8..f628cb4 100644 --- a/notebooks/beginner/notebooks/14_debugging.ipynb +++ b/notebooks/beginner/notebooks/14_debugging.ipynb @@ -12,8 +12,8 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## `import pdb; pdb.set_trace()`\n", - "The basic use case for debugging is that you want to stop the execution of your program at some certain point and monitor variable values or program execution in general from that specific point onward. You stop the execution at the point you want by setting a breakpoint into code by `import pdb; pdb.set_trace()` (note in Python versions >= 3.7, there's a shortcut: `breakpoint()`).\n", + "## `breakpoint()`\n", + "The basic use case for debugging is that you want to stop the execution of your program at some certain point and monitor variable values or program execution in general from that specific point onward. You stop the execution at the point you want by setting a breakpoint into code by `breakpoint()`.\n", "\n", "When you execute your program, the execution will stop at this point and will enter to interactive debugger session. You can add as many breakpoints into your code as you want." ] @@ -41,7 +41,7 @@ "metadata": {}, "source": [ "## Let's see how it works\n", - "Uncomment the `import pdb; pdb.set_trace()` lines and execute the cell. Execute the program line by line by using the commands defined above. Try all the above mentioned commands at least once. Pay attention to the difference between `n` and `s`." + "Uncomment the `Pdb().set_trace()` (this is the Jupyter notebook equivalent for `breakpoint()`) lines and execute the cell. Execute the program line by line by using the commands defined above. Try all the above mentioned commands at least once. Pay attention to the difference between `n` and `s`." ] }, { @@ -50,6 +50,9 @@ "metadata": {}, "outputs": [], "source": [ + "from IPython.core.debugger import Pdb\n", + "\n", + "\n", "class SuperGreeter:\n", " def __init__(self, people_to_greet):\n", " self.people = people_to_greet\n", @@ -68,7 +71,7 @@ " print(greeting)\n", "\n", " def _greet_street_style(self, name):\n", - " # import pdb; pdb.set_trace() # UNCOMMENT\n", + " # Pdb().set_trace() # UNCOMMENT\n", " name = name.upper()\n", " print(f\"WASSUP {name}!?\")\n", "\n", @@ -78,7 +81,7 @@ "\n", "def main():\n", " people = [\"John Doe\", \"Donald\", \"Lisa\", \"alex\"]\n", - " # import pdb; pdb.set_trace() # UNCOMMENT\n", + " # Pdb().set_trace() # UNCOMMENT\n", " greeter = SuperGreeter(people)\n", " greeter.greet()\n", "\n", @@ -89,7 +92,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -103,7 +106,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, From d3633a0d47857ad639ef4d83868c29311afd98c1 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Sat, 22 Apr 2023 14:55:42 +0300 Subject: [PATCH 22/30] Use ZoneInfo from the Standard Library --- .../exercises/15_std_lib1_exercise.ipynb | 20 ++++--------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/notebooks/beginner/exercises/15_std_lib1_exercise.ipynb b/notebooks/beginner/exercises/15_std_lib1_exercise.ipynb index 4897a12..8b059cf 100644 --- a/notebooks/beginner/exercises/15_std_lib1_exercise.ipynb +++ b/notebooks/beginner/exercises/15_std_lib1_exercise.ipynb @@ -1,17 +1,5 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# pytz will be needed in the exercise\n", - "import sys\n", - "\n", - "!{sys.executable} -m pip install pytz" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -31,7 +19,7 @@ "outputs": [], "source": [ "import datetime as dt\n", - "import pytz\n", + "from zoneinfo import ZoneInfo, available_timezones\n", "\n", "NAIVE_DT = dt.datetime(2000, 1, 1, 10)" ] @@ -51,7 +39,7 @@ }, "outputs": [], "source": [ - "for tz in pytz.all_timezones:\n", + "for tz in available_timezones():\n", " print(tz)" ] }, @@ -96,7 +84,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -110,7 +98,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, From 0381fb0bd02599a873867ffae1f3d577041fc11c Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Sat, 22 Apr 2023 14:56:10 +0300 Subject: [PATCH 23/30] Use f-strings --- notebooks/beginner/notebooks/12_exceptions.ipynb | 4 +--- .../intermediate/notebooks/01_pytest_fixtures.ipynb | 3 +-- .../intermediate/notebooks/03_idiomatic_misc1.ipynb | 10 +++------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/notebooks/beginner/notebooks/12_exceptions.ipynb b/notebooks/beginner/notebooks/12_exceptions.ipynb index a50fc25..f062793 100644 --- a/notebooks/beginner/notebooks/12_exceptions.ipynb +++ b/notebooks/beginner/notebooks/12_exceptions.ipynb @@ -129,9 +129,7 @@ "# Dummy example how to use your custom exception\n", "def secret_calculation(number1, number2):\n", " if number1 < 0 or number2 < 0:\n", - " msg = \"Negative number in at least one of the parameters: {}, {}\".format(\n", - " number1, number2\n", - " )\n", + " msg = f\"Negative number in at least one of the parameters: {number1}, {number2}\"\n", " raise NegativeNumbersNotSupported(msg)\n", "\n", " return math.sqrt(number1) + math.sqrt(number2)\n", diff --git a/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb index f1fdc2f..8bf6da0 100644 --- a/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb +++ b/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb @@ -102,8 +102,7 @@ " pass\n", " \n", " def test_some_other_stuff(self, other_fixture):\n", - " print('here we use also other_fixture which returns: {}'.format(other_fixture))\n", - " pass" + " print(f'here we use also other_fixture which returns: {other_fixture}')" ] }, { diff --git a/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb b/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb index ad6c8d1..437343e 100644 --- a/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb +++ b/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb @@ -414,11 +414,7 @@ "outputs": [], "source": [ "def show_person_details(name, is_gangster, is_hacker, age):\n", - " print(\n", - " \"name: {}, gangster: {}, hacker: {}, age: {}\".format(\n", - " name, is_gangster, is_hacker, age\n", - " )\n", - " )" + " print(f\"name: {name}, gangster: {is_gangster}, hacker: {is_hacker}, age: {age}\")" ] }, { @@ -595,7 +591,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", + "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, @@ -609,7 +605,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.5.4" + "version": "3.11.0" } }, "nbformat": 4, From dbf5aafd883d56bd60ebd885714944da552178a1 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Sat, 22 Apr 2023 14:59:56 +0300 Subject: [PATCH 24/30] RE-generate htmls --- notebooks/beginner/html/01_strings.html | 35 ++-- notebooks/beginner/html/02_numbers.html | 6 +- notebooks/beginner/html/03_conditionals.html | 160 +++++------------ notebooks/beginner/html/04_lists.html | 35 ++-- notebooks/beginner/html/05_dictionaries.html | 54 +++--- notebooks/beginner/html/06_for_loops.html | 4 +- notebooks/beginner/html/07_functions.html | 10 +- notebooks/beginner/html/08_testing1.html | 71 ++++---- notebooks/beginner/html/10_file_io.html | 43 +++-- notebooks/beginner/html/11_classes.html | 26 ++- notebooks/beginner/html/12_exceptions.html | 18 +- .../html/13_modules_and_packages.html | 6 +- notebooks/beginner/html/14_debugging.html | 19 ++- notebooks/beginner/html/15_std_lib.html | 161 ++++++------------ notebooks/beginner/html/16_testing2.html | 99 +++++------ .../intermediate/html/01_idiomatic_loops.html | 2 +- .../intermediate/html/01_pytest_fixtures.html | 132 +++++++------- notebooks/intermediate/html/01_std_lib2.html | 14 +- .../intermediate/html/02_idiomatic_dicts.html | 4 +- .../intermediate/html/03_idiomatic_misc1.html | 10 +- .../intermediate/html/04_idiomatic_misc2.html | 24 +-- 21 files changed, 377 insertions(+), 556 deletions(-) diff --git a/notebooks/beginner/html/01_strings.html b/notebooks/beginner/html/01_strings.html index 5355ce0..d2bc0e8 100644 --- a/notebooks/beginner/html/01_strings.html +++ b/notebooks/beginner/html/01_strings.html @@ -15481,7 +15481,7 @@

str.replace() @@ -15493,8 +15493,11 @@

str.format()In [9]: @@ -15531,13 +15535,7 @@

str.format()In [10]: @@ -15605,7 +15602,7 @@

str.join()In [12]: diff --git a/notebooks/beginner/html/02_numbers.html b/notebooks/beginner/html/02_numbers.html index ae0fc6e..b80b9ac 100644 --- a/notebooks/beginner/html/02_numbers.html +++ b/notebooks/beginner/html/02_numbers.html @@ -15134,7 +15134,7 @@

int

@@ -15148,7 +15148,7 @@

Functions< @@ -15178,7 +15178,7 @@

Arguments< @@ -15351,9 +15351,7 @@

Creating your custom exceptions# Dummy example how to use your custom exception def secret_calculation(number1, number2): if number1 < 0 or number2 < 0: - msg = "Negative number in at least one of the parameters: {}, {}".format( - number1, number2 - ) + msg = f"Negative number in at least one of the parameters: {number1}, {number2}" raise NegativeNumbersNotSupported(msg) return math.sqrt(number1) + math.sqrt(number2) diff --git a/notebooks/beginner/html/13_modules_and_packages.html b/notebooks/beginner/html/13_modules_and_packages.html index db32a4d..a347b2a 100644 --- a/notebooks/beginner/html/13_modules_and_packages.html +++ b/notebooks/beginner/html/13_modules_and_packages.html @@ -15170,13 +15170,13 @@

How to use

Let's consider that banana.py file contains:

def get_available_brands():
-    return ['chiquita']
+    return ["chiquita"]
 
 
 class Banana:
-    def __init__(self, brand='chiquita'):
+    def __init__(self, brand="chiquita"):
         if brand not in get_available_brands():
-            raise ValueError('Unkown brand: {}'.format(brand))
+            raise ValueError(f"Unknown brand: {brand}")
         self._brand = brand
 
diff --git a/notebooks/beginner/html/14_debugging.html b/notebooks/beginner/html/14_debugging.html index 0ce26e2..096fded 100644 --- a/notebooks/beginner/html/14_debugging.html +++ b/notebooks/beginner/html/14_debugging.html @@ -15122,7 +15122,7 @@

Debugging with @@ -15157,7 +15157,7 @@

Useful commands @@ -15170,7 +15170,10 @@

Let's see how it worksIn [1]: @@ -15232,8 +15225,8 @@

strftime() -
2023/04/19-10:15:30
-date: 2023-04-19 time:10:15:30
+
2023/04/22-14:56:40
+date: 2023-04-22 time:14:56:40
 
@@ -15263,7 +15256,7 @@

strptime()
my_dt = dt.datetime.strptime("2000-01-01 10:00:00", "%Y-%m-%d %H:%M:%S")
-print("my_dt: {}".format(my_dt))
+print(f"my_dt: {my_dt}")
 
@@ -15313,12 +15306,12 @@

tomorrow = local_now + dt.timedelta(days=1)
-print("tomorrow this time: {}".format(tomorrow))
+print(f"tomorrow this time: {tomorrow}")
 
 delta = tomorrow - local_now
-print("tomorrow - now = {}".format(delta))
-print("days: {}, seconds: {}".format(delta.days, delta.seconds))
-print("total seconds: {}".format(delta.total_seconds()))
+print(f"tomorrow - now = {delta}")
+print(f"days: {delta.days}, seconds: {delta.seconds}")
+print(f"total seconds: {delta.total_seconds()}")
 
@@ -15338,7 +15331,7 @@

-
tomorrow this time: 2023-04-20 10:15:30.717348
+
tomorrow this time: 2023-04-23 14:56:40.502649
 tomorrow - now = 1 day, 0:00:00
 days: 1, seconds: 0
 total seconds: 86400.0
@@ -15357,8 +15350,7 @@ 

@@ -15368,69 +15360,27 @@

Working with timezones - - - - -

@@ -15561,7 +15561,7 @@

try - finallyreturn result -print("return value: {}".format(magical_calculation())) +print(f"return value: {magical_calculation()}")

@@ -15623,7 +15623,7 @@

This is better return result -print("return value: {}".format(magical_calculation())) +print(f"return value: {magical_calculation()}")

@@ -15699,13 +15699,13 @@

Use context managers when possible
try:
     some_file = open("tmp.txt", "w")
-    print("the file is now open: {}".format(not some_file.closed))
+    print(f"the file is now open: {not some_file.closed}")
 
     # here would be some logic
 
 finally:
     some_file.close()
-    print("now it's closed: {}".format(some_file.closed))
+    print(f"now it's closed: {some_file.closed}")
 
@@ -15755,11 +15755,11 @@

Use context manager in - - - - - - - - - - - - - - - - diff --git a/notebooks/beginner/html/11_classes.html b/notebooks/beginner/html/11_classes.html index 23acab0..7404906 100644 --- a/notebooks/beginner/html/11_classes.html +++ b/notebooks/beginner/html/11_classes.html @@ -15166,7 +15166,7 @@

-
my_instance: <__main__.MyFirstClass object at 0x10e7bc410>
+
my_instance: <__main__.MyFirstClass object at 0x10d893220>
 type: <class '__main__.MyFirstClass'>
 my_instance.name: John Doe
 
diff --git a/notebooks/beginner/html/15_std_lib.html b/notebooks/beginner/html/15_std_lib.html index 844d3a6..88e5232 100644 --- a/notebooks/beginner/html/15_std_lib.html +++ b/notebooks/beginner/html/15_std_lib.html @@ -15168,11 +15168,11 @@

-
local now: 2023-04-22 14:56:40.502649
-utc now: 2023-04-22 11:56:40.502813
-2023 4 22 14 56 40
-date: 2023-04-22
-time: 14:56:40.502649
+
local now: 2023-04-24 13:19:22.350525
+utc now: 2023-04-24 10:19:22.350692
+2023 4 24 13 19 22
+date: 2023-04-24
+time: 13:19:22.350525
 
@@ -15225,8 +15225,8 @@

strftime() -
2023/04/22-14:56:40
-date: 2023-04-22 time:14:56:40
+
2023/04/24-13:19:22
+date: 2023-04-24 time:13:19:22
 
@@ -15331,7 +15331,7 @@

-
tomorrow this time: 2023-04-23 14:56:40.502649
+
tomorrow this time: 2023-04-25 13:19:22.350525
 tomorrow - now = 1 day, 0:00:00
 days: 1, seconds: 0
 total seconds: 86400.0
@@ -15400,10 +15400,10 @@ 

Working with timezones -
naive utc now: 2023-04-22 11:56:40.575404, tzinfo: None
-utc now: 2023-04-22 11:56:40.575404+00:00, tzinfo: UTC
-Paris: 2023-04-22 13:56:40.575404+02:00, tzinfo: Europe/Paris
-New York: 2023-04-22 07:56:40.575404-04:00, tzinfo: America/New_York
+
naive utc now: 2023-04-24 10:19:22.431004, tzinfo: None
+utc now: 2023-04-24 10:19:22.431004+00:00, tzinfo: UTC
+Paris: 2023-04-24 12:19:22.431004+02:00, tzinfo: Europe/Paris
+New York: 2023-04-24 06:19:22.431004-04:00, tzinfo: America/New_York
 
@@ -15529,9 +15529,8 @@

Logging expections
ERROR:root:All went south in my calculation
 Traceback (most recent call last):
-  File "/var/folders/q4/_vnp7m_d625g5prgrz28h_fr0000gn/T/ipykernel_46498/3366486048.py", line 2, in <module>
+  File "/var/folders/q4/_vnp7m_d625g5prgrz28h_fr0000gn/T/ipykernel_59325/3366486048.py", line 2, in <module>
     path_calculation = 1 / 0
-                       ~~^~~
 ZeroDivisionError: division by zero
 
@@ -15593,8 +15592,8 @@

Formatting log entries -
2023-04-22 14:56:40,601 | MyLogger     | WARNING    | Something bad is going to happen
-2023-04-22 14:56:40,602 | MyLogger     | ERROR      | Uups, it already happened
+
2023-04-24 13:19:22,459 | MyLogger     | WARNING    | Something bad is going to happen
+2023-04-24 13:19:22,460 | MyLogger     | ERROR      | Uups, it already happened
 
@@ -15701,8 +15700,8 @@

-
random integer between 1-100: 18
-random float between 0-1: 0.5674405898646947
+
random integer between 1-100: 22
+random float between 0-1: 0.010400736609471939
 
diff --git a/notebooks/beginner/html/16_testing2.html b/notebooks/beginner/html/16_testing2.html index 5c16b2f..64abcec 100644 --- a/notebooks/beginner/html/16_testing2.html +++ b/notebooks/beginner/html/16_testing2.html @@ -15152,39 +15152,43 @@

Testing with -
Requirement already satisfied: pytest in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (7.3.1)
-Requirement already satisfied: iniconfig in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from pytest) (2.0.0)
-Requirement already satisfied: packaging in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from pytest) (23.1)
-Requirement already satisfied: pluggy<2.0,>=0.12 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from pytest) (1.0.0)
+
Requirement already satisfied: pytest in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (7.3.1)
+Requirement already satisfied: exceptiongroup>=1.0.0rc8 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest) (1.1.1)
+Requirement already satisfied: tomli>=1.0.0 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest) (2.0.1)
+Requirement already satisfied: pluggy<2.0,>=0.12 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest) (1.0.0)
+Requirement already satisfied: iniconfig in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest) (2.0.0)
+Requirement already satisfied: packaging in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest) (23.1)
 
-[notice] A new release of pip available: 22.3.1 -> 23.1
+[notice] A new release of pip available: 22.3.1 -> 23.1.1
 [notice] To update, run: pip install --upgrade pip
-Requirement already satisfied: ipytest in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (0.13.1)
-Requirement already satisfied: packaging in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipytest) (23.1)
-Requirement already satisfied: ipython in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipytest) (8.12.0)
-Requirement already satisfied: pytest>=5.4 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipytest) (7.3.1)
-Requirement already satisfied: iniconfig in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from pytest>=5.4->ipytest) (2.0.0)
-Requirement already satisfied: pluggy<2.0,>=0.12 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from pytest>=5.4->ipytest) (1.0.0)
-Requirement already satisfied: backcall in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (0.2.0)
-Requirement already satisfied: decorator in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (5.1.1)
-Requirement already satisfied: jedi>=0.16 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (0.18.2)
-Requirement already satisfied: matplotlib-inline in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (0.1.6)
-Requirement already satisfied: pickleshare in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (0.7.5)
-Requirement already satisfied: prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (3.0.38)
-Requirement already satisfied: pygments>=2.4.0 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (2.15.1)
-Requirement already satisfied: stack-data in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (0.6.2)
-Requirement already satisfied: traitlets>=5 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (5.9.0)
-Requirement already satisfied: pexpect>4.3 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (4.8.0)
-Requirement already satisfied: appnope in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from ipython->ipytest) (0.1.3)
-Requirement already satisfied: parso<0.9.0,>=0.8.0 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from jedi>=0.16->ipython->ipytest) (0.8.3)
-Requirement already satisfied: ptyprocess>=0.5 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from pexpect>4.3->ipython->ipytest) (0.7.0)
-Requirement already satisfied: wcwidth in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30->ipython->ipytest) (0.2.6)
-Requirement already satisfied: executing>=1.2.0 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from stack-data->ipython->ipytest) (1.2.0)
-Requirement already satisfied: asttokens>=2.1.0 in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from stack-data->ipython->ipytest) (2.2.1)
-Requirement already satisfied: pure-eval in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from stack-data->ipython->ipytest) (0.2.2)
-Requirement already satisfied: six in /Users/jerrypussinen/.virtualenvs/learn-python-311/lib/python3.11/site-packages (from asttokens>=2.1.0->stack-data->ipython->ipytest) (1.16.0)
+Requirement already satisfied: ipytest in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (0.13.1)
+Requirement already satisfied: pytest>=5.4 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipytest) (7.3.1)
+Requirement already satisfied: ipython in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipytest) (8.12.0)
+Requirement already satisfied: packaging in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipytest) (23.1)
+Requirement already satisfied: exceptiongroup>=1.0.0rc8 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest>=5.4->ipytest) (1.1.1)
+Requirement already satisfied: tomli>=1.0.0 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest>=5.4->ipytest) (2.0.1)
+Requirement already satisfied: pluggy<2.0,>=0.12 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest>=5.4->ipytest) (1.0.0)
+Requirement already satisfied: iniconfig in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pytest>=5.4->ipytest) (2.0.0)
+Requirement already satisfied: pexpect>4.3 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (4.8.0)
+Requirement already satisfied: pygments>=2.4.0 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (2.15.0)
+Requirement already satisfied: jedi>=0.16 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (0.18.2)
+Requirement already satisfied: prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (3.0.38)
+Requirement already satisfied: traitlets>=5 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (5.9.0)
+Requirement already satisfied: pickleshare in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (0.7.5)
+Requirement already satisfied: backcall in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (0.2.0)
+Requirement already satisfied: stack-data in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (0.6.2)
+Requirement already satisfied: matplotlib-inline in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (0.1.6)
+Requirement already satisfied: decorator in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (5.1.1)
+Requirement already satisfied: appnope in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from ipython->ipytest) (0.1.3)
+Requirement already satisfied: parso<0.9.0,>=0.8.0 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from jedi>=0.16->ipython->ipytest) (0.8.3)
+Requirement already satisfied: ptyprocess>=0.5 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from pexpect>4.3->ipython->ipytest) (0.7.0)
+Requirement already satisfied: wcwidth in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from prompt-toolkit!=3.0.37,<3.1.0,>=3.0.30->ipython->ipytest) (0.2.6)
+Requirement already satisfied: asttokens>=2.1.0 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from stack-data->ipython->ipytest) (2.2.1)
+Requirement already satisfied: executing>=1.2.0 in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from stack-data->ipython->ipytest) (1.2.0)
+Requirement already satisfied: pure-eval in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from stack-data->ipython->ipytest) (0.2.2)
+Requirement already satisfied: six in /Users/jerrypussinen/.virtualenvs/learn-python/lib/python3.10/site-packages (from asttokens>=2.1.0->stack-data->ipython->ipytest) (1.16.0)
 
-[notice] A new release of pip available: 22.3.1 -> 23.1
+[notice] A new release of pip available: 22.3.1 -> 23.1.1
 [notice] To update, run: pip install --upgrade pip
 
diff --git a/notebooks/intermediate/html/01_pytest_fixtures.html b/notebooks/intermediate/html/01_pytest_fixtures.html index f462fc9..9c65c0d 100644 --- a/notebooks/intermediate/html/01_pytest_fixtures.html +++ b/notebooks/intermediate/html/01_pytest_fixtures.html @@ -15166,39 +15166,43 @@

Efficient use of pytest f @@ -15275,7 +15279,7 @@

Parametrizing fixtures/foo/bar.txt ./bar/baz.txt . -2 passed in 0.02s +2 passed in 0.01s

From c0d0c4a6f1ef20f46f6248f68b42f66336c02d15 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Mon, 24 Apr 2023 13:54:14 +0300 Subject: [PATCH 28/30] Fix links --- README.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index fac79a2..a0a0071 100644 --- a/README.md +++ b/README.md @@ -51,21 +51,21 @@ See [contributing](https://github.com/jerry-git/learn-python3/blob/master/CONTRI #### Idiomatic Python Python is a powerful language which contains many features not presented in most other programming languages. Idiomatic section will cover some of these Pythonic features in detail. These materials are especially useful for people with background in other programming languages. -1. [Idiomatic loops](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/idiomatic_loops.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/idiomatic_loops.ipynb) -1. [Idiomatic dictionaries](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/idiomatic_dicts.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/idiomatic_dicts.ipynb) -1. [Idiomatic Python - miscellaneous part 1](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/idiomatic_misc1.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/idiomatic_misc1.ipynb) -1. [Idiomatic Python - miscellaneous part 2](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/idiomatic_misc2.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/idiomatic_misc2.ipynb) -1. Idiomatic Python exercise [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/exercises/idiomatic_python_exercise.ipynb) +1. [Idiomatic loops](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/01_idiomatic_loops.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/01_idiomatic_loops.ipynb) +2. [Idiomatic dictionaries](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/02_idiomatic_dicts.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/02_idiomatic_dicts.ipynb) +3. [Idiomatic Python - miscellaneous part 1](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/03_idiomatic_misc1.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/03_idiomatic_misc1.ipynb) +4. [Idiomatic Python - miscellaneous part 2](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/04_idiomatic_misc2.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/04_idiomatic_misc2.ipynb) +5. Idiomatic Python exercise [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/exercises/05_idiomatic_python_exercise.ipynb) #### Step up your `pytest` game -1. [Efficient use of fixtures](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/pytest_fixtures.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/pytest_fixtures.ipynb) +1. [Efficient use of fixtures](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/01_pytest_fixtures.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/01_pytest_fixtures.ipynb) #### Best practices A list of best development practices for Python projects. Most of the practices listed here are also applicable for other languages, however the presented tooling focuses mainly on Python. -1. [Best practices](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/best_practices.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/best_practices.ipynb) +1. [Best practices](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/01_best_practices.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/01_best_practices.ipynb) #### General topics -1. [Goodies of the Standard Library - part 2](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/std_lib2.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/std_lib2.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/exercises/std_lib2_exercise.ipynb) +1. [Goodies of the Standard Library - part 2](https://jerry-git.github.io/learn-python3/notebooks/intermediate/html/01_std_lib2.html) [[notebook]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/notebooks/01_std_lib2.ipynb) [[exercise]](http://nbviewer.jupyter.org/github/jerry-git/learn-python3/blob/master/notebooks/intermediate/exercises/01_std_lib2_exercise.ipynb) ## Credits From 69afbfccbc049418ee98ed17ccda45c3fa42b877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=BCrgen=20Key?= Date: Mon, 24 Apr 2023 18:53:13 +0200 Subject: [PATCH 29/30] re #12 --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a0a0071..59da373 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,16 @@ This repository contains a collection of materials for teaching/learning Python If you can not access Python and/or Jupyter Notebook on your machine, you can still follow the web based materials. However, you should be able to use Jupyter Notebook in order to complete the exercises. -#### Usage +#### Usage (locally) 1. Clone or download this repository. 2. Run `jupyter notebook` command in your command line in the repository directory. 3. Jupyter Notebook session will open in the browser and you can start navigating through the materials. +#### Usage (Binder in the cloud) + +You can also just use [Binder:](https://mybinder.org/) By clicking of this [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jerry-git/learn-python3/master) badge, the project is opened in a Jupyter instance in the cloud and you can then navigate to the folders containing the notebooks and start them each and interactively explorte them! + #### Contributing See [contributing](https://github.com/jerry-git/learn-python3/blob/master/CONTRIBUTING.md) guide. From bdc2e297185d9c0440ad0867cd5fbb8623e3f8d0 Mon Sep 17 00:00:00 2001 From: Jerry Pussinen Date: Tue, 25 Apr 2023 09:02:37 +0300 Subject: [PATCH 30/30] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 59da373..ca05ac1 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ If you can not access Python and/or Jupyter Notebook on your machine, you can st #### Usage (Binder in the cloud) -You can also just use [Binder:](https://mybinder.org/) By clicking of this [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jerry-git/learn-python3/master) badge, the project is opened in a Jupyter instance in the cloud and you can then navigate to the folders containing the notebooks and start them each and interactively explorte them! +You can also just use [Binder:](https://mybinder.org/) By clicking of this [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jerry-git/learn-python3/master) badge, the project is opened in a Jupyter instance in the cloud and you can then navigate to the folders containing the notebooks and start them each and interactively explore them! #### Contributing See [contributing](https://github.com/jerry-git/learn-python3/blob/master/CONTRIBUTING.md) guide.