├── .editorconfig ├── .gitignore ├── LICENSE ├── Pipfile ├── Pipfile.lock ├── README.md ├── config_files ├── __init__.py ├── bkp_readme.md ├── config_by_environment │ ├── __init__.py │ ├── config.py │ └── main.py ├── dynamic_loading │ ├── __init__.py │ ├── config.py │ ├── main.py │ └── setting │ │ ├── __init__.py │ │ └── config.py ├── external_config_file │ ├── __init__.py │ ├── config.ini │ ├── config.json │ ├── main_with_ini.py │ └── main_with_json.py └── main_with_env.py ├── docs └── seminario_python-pt-br.pdf ├── environment ├── container │ ├── .dockerignore │ └── Dockerfile ├── create_requirements_from_notebook.sh ├── how-prepare-python-env-in-anywhere.md ├── jupyter_notebook_config.py ├── makefile └── test_environment.py ├── example_imports ├── cli.py ├── data │ └── test.xml └── structure │ ├── files.py │ └── structure.py ├── exercises ├── find_path │ ├── README.md │ ├── app │ │ └── find_files.py │ └── test │ │ └── test_find_files.py └── multithreading │ ├── README.md │ ├── app │ └── pick_and_clean_fruit.py │ ├── flow.png │ └── test │ └── test_pick_and_clean_fruit.py ├── fundamentals ├── Importing.py ├── class.py ├── example_stacktrace.py ├── how_use_arguments.py ├── how_use_docstrings.py ├── how_use_iterators.py ├── how_use_unpacking_argument.py └── unpacking_arguments_query.py ├── images ├── 1.png ├── 2.png ├── 3.png ├── Python3VersionChange.jpg ├── Python_3._The_standard_type_hierarchy.png ├── __doc__.png ├── array-and-lists.svg ├── bashrc_python.png ├── change_python.gif ├── comp-interpreter.png ├── config.jpg ├── cpython.png ├── create_virtualenv.gif ├── debug.gif ├── env.png ├── freeze.png ├── from.png ├── git_logo.png ├── help().png ├── icon_ubuntu.png ├── icon_windows.png ├── icons_test.png ├── import.png ├── in-production.gif ├── install_python.gif ├── interpreter.png ├── jython.jpg ├── list_versions.gif ├── multithread.png ├── operadores.png ├── org_python.jpg ├── org_python_virtualenv.jpg ├── pipe.gif ├── pipenv.gif ├── pipenv.png ├── pipenv_lock.gif ├── precedencia.png ├── pylint_example.gif ├── python.png ├── python_1.PNG ├── python_2.PNG ├── python_3.PNG ├── python_4.PNG ├── python_5.PNG ├── python_6.PNG ├── python_alternatives.png ├── python_logo.png ├── requeriments.png ├── show_path_lib.png ├── tipos.png ├── types.png ├── venv.png ├── version_python.gif ├── virtual_env_p3.png ├── virtualenv.gif ├── virtualenv.jpeg ├── virtualenv.jpg ├── virtualenv.png ├── which_python.gif ├── windows_python_4.png ├── windows_python_5.png ├── windows_python_6.png └── zen.png ├── logging_config ├── logging_config.ini └── test_logging.py └── structure_python_files ├── 1-isolated_function.py ├── 2-with__main__.py ├── 3-basic_structure.py ├── 4-complete.py ├── 5-complete_with_class.py └── readme.md /.editorconfig: -------------------------------------------------------------------------------- 1 | ############################################################################## 2 | # Helps Coding Styles 3 | 4 | 5 | # References: 6 | # https://editorconfig.org/ 7 | # https://github.com/editorconfig/editorconfig/wiki/Projects-Using-EditorConfig 8 | ############################################################################## 9 | 10 | # top-most EditorConfig file 11 | root = true 12 | 13 | # Unix-style newlines with a newline ending every file 14 | [*] 15 | 16 | # Always indent by 4 characters 17 | indent_size = 4 18 | 19 | # Docstrings and comments use max_line_length = 79 20 | max_line_length = 79 21 | 22 | # Enforce Unix style line endings (\n only) 23 | end_of_line = lf 24 | 25 | # Set default charset 26 | charset = utf-8 27 | 28 | # Always end files with a blank line 29 | insert_final_newline = true 30 | 31 | # Force space characters for indentation 32 | indent_style = space 33 | 34 | # Remove whitespace characters at the end of line 35 | trim_trailing_whitespace = true 36 | 37 | 38 | # HTML files 39 | [*.html] 40 | indent_size = 2 41 | 42 | # JSON files 43 | [*.json] 44 | indent_size = 2 45 | insert_final_newline = ignore 46 | 47 | # JavaScript files 48 | [**.min.js] 49 | indent_style = ignore 50 | insert_final_newline = ignore 51 | 52 | # Makefiles 53 | [Makefile] 54 | indent_style = tab 55 | 56 | # Batch files 57 | [*.bat] 58 | indent_style = tab 59 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | 49 | # Translations 50 | *.mo 51 | *.pot 52 | 53 | # Django stuff: 54 | *.log 55 | local_settings.py 56 | 57 | # Flask stuff: 58 | instance/ 59 | .webassets-cache 60 | 61 | # Scrapy stuff: 62 | .scrapy 63 | 64 | # Sphinx documentation 65 | docs/_build/ 66 | 67 | # PyBuilder 68 | target/ 69 | 70 | # Jupyter Notebook 71 | .ipynb_checkpoints 72 | 73 | # IPython 74 | profile_default/ 75 | ipython_config.py 76 | 77 | # pyenv 78 | .python-version 79 | 80 | # celery beat schedule file 81 | celerybeat-schedule 82 | 83 | # SageMath parsed files 84 | *.sage.py 85 | 86 | # Environments 87 | .env 88 | .venv 89 | env/ 90 | venv/ 91 | venv_python/ 92 | ENV/ 93 | env.bak/ 94 | venv.bak/ 95 | 96 | # Virtualenv 97 | .Python 98 | [Bb]in 99 | [Ii]nclude 100 | [Ll]ib 101 | [Ll]ib64 102 | [Ll]ocal 103 | [Ss]cripts 104 | pyvenv.cfg 105 | .venv 106 | pip-selfcheck.json 107 | 108 | # Spyder project settings 109 | .spyderproject 110 | .spyproject 111 | 112 | # Rope project settings 113 | .ropeproject 114 | 115 | # mkdocs documentation 116 | /site 117 | 118 | # mypy 119 | .mypy_cache/ 120 | .dmypy.json 121 | dmypy.json 122 | 123 | # Pyre type checker 124 | .pyre/ 125 | 126 | # IDEs and editors 127 | .vscode/* 128 | .idea/* 129 | 130 | # paths 131 | notebooks/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Bruno Campos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | 8 | [dev-packages] 9 | 10 | [requires] 11 | python_version = "3.8" 12 | -------------------------------------------------------------------------------- /Pipfile.lock: -------------------------------------------------------------------------------- 1 | { 2 | "_meta": { 3 | "hash": { 4 | "sha256": "7f7606f08e0544d8d012ef4d097dabdd6df6843a28793eb6551245d4b2db4242" 5 | }, 6 | "pipfile-spec": 6, 7 | "requires": { 8 | "python_version": "3.8" 9 | }, 10 | "sources": [ 11 | { 12 | "name": "pypi", 13 | "url": "https://pypi.org/simple", 14 | "verify_ssl": true 15 | } 16 | ] 17 | }, 18 | "default": {}, 19 | "develop": {} 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Understanding the Python Ecosystem 2 | 3 | ![License](https://img.shields.io/badge/Code%20License-MIT-blue.svg) 4 | 6 | This project focuses on understanding the language ecosystem, not getting into programming details. 7 | 8 | # Summary 9 | 10 | :sunrise_over_mountains: **_Python's Habitat_** 11 | 12 | This topic describes how to set up the environment for Python development. 13 | - [Preparing the Environment for the Python](#preparing-the-environment-for-the-python) 14 | - [Check Python Configuration](#check-python-configuration) 15 | - [Advanced settings of Python](#advanced-settings-of-python) 16 | - [What is a virtual environment and how it works](#What-is-a-virtual-environment-and-how-it-works) 17 | 18 |
19 | 20 | :snake: **_Python's Taxonomy_** 21 | 22 | This topic describes features of the pattern of Python projects. 23 | - [Package manager](#package-manager) 24 | - [Requirements file](#requirements-file) 25 | - [Deterministic build](#deterministic-build) 26 | 27 | 28 |
29 | 30 | :anger: **_Python's Behavior_** 31 | 32 | This topic describes how the language is designed and how it works. 33 | - [Compiler and interpreter](#compiler-and-interpreter) 34 | - [How Python runs a program](#how-python-runs-a-program) 35 | - [How Python search path module](#how-python-search-path-module) 36 | - [How Python manages process and threads](#how-python-manages-process-and-threads) 37 | - [How Python manages memory](#how-python-manages-memory) 38 | - [How to deeply understand Python code execution (debug)](#how-to-deeply-understand-python-code-execution) 39 | 40 | 46 | 47 |
48 | 49 | :bug: **_Python's Feeding_** 50 | 51 | This topic describes static code analysis, formatting patterns and style guides. 52 | - [Static code analysis](#static-code-analysis) 53 | - [Principal style guides](#principal-style-guides) 54 | - [Knobs (Google YAPF)](https://github.com/google/yapf#id11) 55 | - [My Knobs](#my-knobs) 56 | - [Docstrings](#docstrings) 57 | 58 | 60 | 61 | 62 |
63 | 64 | :mag: **_Python's Other Features_** 65 | 66 | Extra topics. 67 | - [Awesome Python](https://github.com/vinta/awesome-python) 68 | - [Why Is CPython Written in C and Not Python?](https://realpython.com/cpython-source-code-guide/#why-is-cpython-written-in-c-and-not-python) 69 | 70 |
71 |
72 |
73 | 74 | --- 75 | 76 |
77 | 78 | ## **Preparing the Environment for the Python** 79 | 80 |
81 | Linux 82 | 83 | Python needs a set of tools that are system requirements. If necessary, install these requirements with this command: 84 | ```bash 85 | sudo apt update 86 | 87 | sudo apt install\ 88 | software-properties-common\ 89 | build-essential\ 90 | libffi-dev\ 91 | python3-pip\ 92 | python3-dev\ 93 | python3-venv\ 94 | python3-setuptools\ 95 | python3-pkg-resources 96 | ``` 97 | 98 | Now, the environment is done to install Python 99 | ```bash 100 | sudo apt install python 101 | ``` 102 |
103 |
104 | 105 |
106 | Windows 107 | 108 | On Windows, I recommend using the package manager [chocolatey](https://chocolatey.org/) and setting your Powershell to work as admin. See [this](devpos/infra-as-code) tutorial. 109 | 110 | Now, install Python 111 | ```powershell 112 | choco install python 113 | ``` 114 | 115 | 116 | 117 | 118 |
119 | 120 | Test 121 | ```powershell 122 | python --version 123 | ``` 124 | 125 | 126 | 127 |
128 |
129 | 130 | --- 131 | 132 |
133 | 134 | ## **Check Python Configuration** 135 | ### Check **current version** 136 | 137 |
138 | Watch 139 | 140 |
141 | 142 | ```bash 143 | python --version 144 | ``` 145 | 146 | ### Check **where** installed Python 147 |
148 | Watch 149 | 150 |
151 | 152 | ```bash 153 | which python 154 | ``` 155 | 156 | ### Check **which Python versions** are installed 157 |
158 | Watch 159 | 160 |
161 | 162 | ```bash 163 | sudo update-alternatives --list python 164 | ``` 165 | 166 | --- 167 | 168 |
169 | 170 | ## **Advanced settings of Python** 171 | 172 |
173 | Install multiples Python versions 174 | 175 | Sometimes you might work on different projects simultaneously with different versions of Python. Normally using Anaconda is the easiest solution, however, there are restrictions. 176 | 177 | 1. Add repository 178 |
179 | Watch 180 | 181 |
182 | 183 | This PPA contains more recent Python versions packaged for Ubuntu. 184 | ```bash 185 | sudo add-apt-repository ppa:deadsnakes/ppa -y 186 | ``` 187 | 188 | 2. Update packages 189 | ```bash 190 | sudo apt update -y 191 | ``` 192 | 193 | 3. Check which Python version is installed 194 | ```bash 195 | python --version 196 | ``` 197 | 198 | 4. Install Python 199 | ```bash 200 | sudo apt install python3. 201 | ``` 202 |
203 |
204 | 205 |
206 | Install multiples Python versions Using Pyenv 207 | 208 | 209 | 1. Add dependencies 210 | ```bash 211 | sudo apt install curl -y 212 | ``` 213 | 214 | 2. Update packages 215 | ```bash 216 | sudo apt update -y 217 | ``` 218 | 219 | 3. Install pyenv 220 | ```bash 221 | curl https://pyenv.run | bash 222 | ``` 223 | 224 | 4. Add these three lines from .bashrc or .zhshrc 225 | ```bash 226 | export PATH="$HOME/.pyenv/bin:$PATH" 227 | eval "$(pyenv init --path)" 228 | eval "$(pyenv virtualenv-init -)" 229 | ``` 230 | 231 | 5. Open a new terminal and execute 232 | ```bash 233 | exec $SHELL 234 | pyenv --version 235 | ``` 236 | 237 |
238 |
239 | 240 |
241 | Change system's Python 242 | 243 | Before installing other versions of Python it's necessary to set which system's Python will be used. 244 | 245 | 1. Use `update-alternatives` 246 | 247 | It's possible use the `update-alternatives` command to set priority to different versions of the same software installed in Ubuntu systems. Now, define priority of versions: 248 | 249 | ```bash 250 | sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.11 1 251 | 252 | sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.10 2 253 | 254 | sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 3 255 | 256 | sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.6 4 257 | ``` 258 | 259 | In directory `/usr/bin` will be create simbolic link: `/usr/bin/python -> /etc/alternatives/python*` 260 | 261 | 2. Choose version 262 | 263 |
264 | Watch 265 | 266 |
267 | 268 | ```bash 269 | sudo update-alternatives --config python 270 | ``` 271 | 272 | 3. Test 273 | ```bash 274 | python --version 275 | ``` 276 |
277 |
278 | 279 | 280 |
281 | Change Python2 to Python3 282 | 283 | If return Python **2**, try set a alias in `/home/$USER/.bashrc`, see this [example](https://github.com/brunocampos01/home-sweet-home/blob/master/config/.bashrc). 284 | 285 | ```bash 286 | alias python=python3 287 | ``` 288 | 289 | **NOTE:** 290 | The important thing to realize is that Python 3 is not backwards compatible with Python 2. This means that if you try to run Python 2 code as Python 3, it will probably break. 291 | 292 |
293 |
294 | 295 | 296 |
297 | Set Python's Environment Variables 298 | 299 | 300 | - `PYTHONPATH` is an environment variable which you can set to add additional directories where python will look for modules and packages. Example: [Apache Airflow](https://airflow.apache.org/) read `dag/` folder and add automatically any file that is in this directory. 301 | - To interpreter `PYTHONHOME` indicate standard packages. 302 | 303 |
304 | 305 |
306 | Set PYTHONPATH 307 | 308 | 1. Open profile 309 | ```bash 310 | sudo vim ~/.bashrc 311 | ``` 312 | 313 | 2. Insert Python PATH 314 | ```bash 315 | export PYTHONHOME=/usr/bin/python 316 | ``` 317 | 318 | 3. Update profile/bashrc 319 | ```bash 320 | source ~/.bashrc 321 | ``` 322 | 323 | 4. Test 324 | ```bash 325 | >>> import sys 326 | >>> from pprint import pprint 327 | >>> pprint(sys.path) 328 | ['', 329 | '/usr/lib/python311.zip', 330 | '/usr/lib/python3.11', 331 | '/usr/lib/python3.11/lib-dynload', 332 | '/usr/local/lib/python3.11/dist-packages', 333 | '/usr/lib/python3/dist-packages'] 334 | ``` 335 | 336 | Example with Apache Airflow 337 | ```bash 338 | >>> import sys 339 | >>> from pprint import pprint 340 | >>> pprint(sys.path) 341 | ['', 342 | '/home/project_name/dags', 343 | '/home/project_name/config', 344 | '/home/project_name/utilities', 345 | ... 346 | ] 347 | ``` 348 |
349 |
350 |
351 | 352 | 353 | --- 354 | 355 |
356 | 357 | ## **What is a virtual environment and how it works** 358 | Python can run in a virtual environment with **isolation** from the system. 359 | 360 | 361 | 362 | ###### Image source: https://vincenttechblog.com/fix-change-python-virtualenv-settings/ 363 | 364 |
365 | 366 |
367 | Arquitecture of Execution 368 | 369 | 370 | 371 |
372 | 373 | Virtualenv enables us to create multiple Python environments which are isolated from the global Python environment as well as from each other. 374 | 375 | 376 | 377 |
378 | 379 | When Python is initiating, it analyzes the path of its binary. In a virtual environment, it's actually just a copy or Symbolic link to your system's Python binary. Next, set the `sys.prefix` location which is used to locate the `site-packages` (third party packages/libraries) 380 | 381 | 382 | 383 | 384 |
385 | 386 | #### **Symbolic link** 387 | - `sys.prefix` points to the virtual environment directory. 388 | - `sys.base.prefix` points to the **non-virtual** environment. 389 | 390 | #### **Folder of virtual environment** 391 | ```bash 392 | ll 393 | 394 | # random.py -> /usr/lib/python3.6/random.py 395 | # reprlib.py -> /usr/lib/python3.6/reprlib.py 396 | # re.py -> /usr/lib/python3.6/re.py 397 | # ... 398 | ``` 399 | 400 | ```bash 401 | tree 402 | 403 | ├── bin 404 | │ ├── activate 405 | │ ├── activate.csh 406 | │ ├── activate.fish 407 | │ ├── easy_install 408 | │ ├── easy_install-3.8 409 | │ ├── pip 410 | │ ├── pip3 411 | │ ├── pip3.8 412 | │ ├── python -> python3.8 413 | │ ├── python3 -> python3.8 414 | │ └── python3.8 -> /Library/Frameworks/Python.framework/Versions/3.8/bin/python3.8 415 | ├── include 416 | ├── lib 417 | │ └── python3.8 418 | │ └── site-packages 419 | └── pyvenv.cfg 420 | ``` 421 | 422 |
423 | 424 |
425 | Create Virtual Environment 426 |
427 | Watch 428 | 429 |
430 | 431 | Create virtual environment 432 | ```bash 433 | virtualenv -p python3 434 | ``` 435 | 436 | Activate 437 | ```bash 438 | source /bin/activate 439 | ``` 440 |
441 |
442 | 443 | --- 444 | 445 |
446 | 447 | ## **Package manager** 448 |
449 | Pipenv 450 | 451 | Create and manage automatically a virtualenv for your projects, as well as adds/removes packages from your Pipfile as you install/uninstall packages. It also generates the ever-important `Pipfile.lock`, which is used to produce deterministic builds. 452 | 453 | #### **Features** 454 | - Deterministic builds 455 | - Separates development and production environment packages into a single file `Pipefile` 456 | - Automatically adds/removes packages from your `Pipfile` 457 | - Automatically create and manage a virtualenv 458 | - Check PEP 508 requirements 459 | - Check installed package safety 460 | 461 | #### **Pipfile X requirements** 462 | ```bash 463 | # Pipfile 464 | 465 | [[source]] 466 | name = "pypi" 467 | url = "https://pypi.org/simple" 468 | verify_ssl = true 469 | 470 | [dev-packages] 471 | 472 | [packages] 473 | requests = "*" 474 | numpy = "==1.18.1" 475 | pandas = "==1.0.1" 476 | wget = "==3.2" 477 | 478 | [requires] 479 | python_version = "3.8" 480 | platform_system = 'Linux' 481 | ``` 482 | 483 | ```bash 484 | # requirements.txt 485 | 486 | requests 487 | matplotlib==3.1.3 488 | numpy==1.18.1 489 | pandas==1.0.1 490 | wget==3.2 491 | ``` 492 | 493 |
494 | 495 | ### **Install** 496 | ```bash 497 | pip3 install --user pipenv 498 | ``` 499 | 500 |
501 | 502 | ### Create Pipfile and virtual environment 503 | 1. Create environment 504 |
505 | Watch 506 | 507 |
508 | 509 | ```bash 510 | pipenv --python 3 511 | ``` 512 | 513 | 2. See **where** virtual environment is installed 514 | ```bash 515 | pipenv --venv 516 | ``` 517 | 518 | 3. Activate environment 519 | ```bash 520 | pipenv run 521 | ``` 522 | 523 | 4. Install packages with Pipefile 524 | ```bash 525 | pipenv install flask 526 | # or 527 | pipenv install --dev flask 528 | ``` 529 | 530 | 5. Create lock file 531 |
532 | Watch 533 | 534 |
535 | 536 | ```bash 537 | pipenv lock 538 | ``` 539 |
540 |
541 | 542 |
543 | Python Package Index 544 | 545 | [Doc Python Package Index](https://pypi.org/) 546 |
547 |
548 | 549 |
550 | Poetry 551 | 552 | [Doc Poetry](https://python-poetry.org/) 553 |
554 |
555 | 556 |
557 | Conda 558 | 559 | [Doc Conda](https://docs.conda.io/en/latest/) 560 |
561 |
562 | 563 | --- 564 | 565 |
566 | 567 | ## **Requirements File** 568 | `Requirements.txt` is file containing a list of items to be installed using pip install. 569 | 570 |
571 | Principal Comands 572 | 573 | 1. Visualize instaled packages 574 | ```bash 575 | pip3 freeze 576 | ``` 577 | 578 | 2. Generate file `requirements.txt` 579 | ```bash 580 | pip3 freeze > requirements.txt 581 | ``` 582 | 583 | 3. Test 584 | ```bash 585 | cat requirements.txt 586 | ``` 587 | 588 | 4. Install packages in requirements 589 | ```bash 590 | pip3 install -r requirements.txt 591 | ``` 592 |
593 |
594 | 595 | --- 596 | 597 |
598 | 599 | ## **Deterministic Build** 600 | 601 | Using pip and `requirements.txt` file, have a **real issue here is that the build isn’t [deterministic](https://pt.wikipedia.org/wiki/Algoritmo_determin%C3%ADstico)**. What I mean by that is, given the same input (the `requirements.txt` file), pip does not always produce the same environment. 602 | 603 | 604 | ### **pip-tools** 605 | A set of command line tools to help you keep your pip-based packages fresh and ensure the deterministic build. 606 | 607 | #### **Features** 608 | - Distinguish direct dependencies and versions 609 | - Freeze a set of exact packages and versions that we know work 610 | - Make it reasonably easy to update packages 611 | - Take advantage of pip's hash checking to give a little more confidence that packages haven't been modified (DNS attack) 612 | - Stable 613 | 614 |
615 | Principal Comands 616 | 617 | 1. Install 618 | ``` 619 | pip install pip-tools 620 | ``` 621 | 622 | 2. Get packages's version 623 | ```bash 624 | pip3 freeze > requirements.in 625 | ``` 626 | 627 | 3. Generate hashes and list dependeces 628 | ```bash 629 | pip-compile --generate-hashes requirements.in 630 | ``` 631 | output: [requirements.txt](requirements.txt) 632 | 633 | 4. Install packages and hash checking 634 | ```bash 635 | pip-compile --generate-hashes requirements.in 636 | ``` 637 |
638 | 639 |
640 | 641 | --- 642 | 643 |
644 | 645 | ## **Compiler and interpreter** 646 | CPython can be defined as both an interpreter and a compiler. 647 | - The **compiler** converts the `.py` source file into a `.pyc` bytecode for the Python virtual machine. 648 | - The **interpreter** executes this bytecode on the virtual machine. 649 | 650 | 651 | 652 |
653 | 654 | 655 | 657 | 658 | ### **CPython's Design** 659 | The principal feature of [CPython](https://en.wikipedia.org/wiki/CPython#:~:text=8%20External%20links-,Design,bytecode%20at%20any%20one%20time.), is that it makes use of a global interpreter lock (GIL). This is a mechanism used in computer-language interpreters to synchronize the execution of threads so that only one native thread can execute at a time. 660 |
661 | Therefore, for a CPU-bound task in Python, single-process multi-thread Python program would not improve the performance. However, this does not mean multi-thread is useless in Python. For a I/O-bound task in Python, multi-thread could be used to improve the program performance. 662 | 663 |
664 | Multithreading in Python 665 | The Python has multithreads despite the GIL. Using Python threading, we are able to make better use of the CPU sitting idle when waiting for the I/O bound, how memory I/O, hard drive I/O, network I/O. 666 | 667 | 668 | 669 |
670 | 671 | This can happen when multiple threads are servicing separate clients. One thread may be waiting for a client to reply, and another may be waiting for a database query to execute, while the third thread is actually processing Python code or other example is read multiples images from disk. 672 | 673 | **NOTE:** we would have to be careful and use locks when necessary. Lock and unlock make sure that only one thread could write to memory at one time, but this will also introduce some overhead. 674 | 675 | 678 | 679 |
680 |
681 | 682 |
683 | Community Consensus 684 | 685 | Removing the GIL would have made **Python 3 slower in comparison to Python 2** in single-threaded performance. Other problem if remove the GIL it's would **broke the existing C extensions** which depend heavily on the solution that the GIL provides. 686 |
687 | Although many proposals have been made to eliminate the GIL, the general consensus has been that in most cases, the advantages of the GIL outweigh the disadvantages; in the few cases where the GIL is a bottleneck, the application should be built around the multiprocessing structure. 688 | 689 |
690 |
691 | 692 | 693 | --- 694 | 695 |
696 | 697 | ## **How Python runs a program** 698 | 1. Tokenize the source code: `Parser/tokenizer.c` 699 | 2. Parse the stream of tokens into an Abstract Syntax Tree (AST): `Parser/parser.c` 700 | 3. Transform AST into a Control Flow Graph: `Python/compile.c` 701 | 4. Emit bytecode based on the Control Flow Graph: `Python/compile.c` 702 | 703 | 704 | --- 705 | 706 |
707 | 708 | ## **How Python search path module** 709 | When Python executes this statement: 710 | ```python 711 | import my_lib 712 | ``` 713 | The interpreter searches `my_lib.py` a list of directories 714 | assembled from the following sources: 715 | - Current directory 716 | - The list of directories contained in the **PYTHONPATH** environment variable 717 | - In directory which Python was is installed. E.g. 718 | 719 | 720 | 721 | The resulting search can be accessed using the **sys** module: 722 | ```python 723 | import sys 724 | 725 | sys.paths 726 | # ['', '/usr/lib/python38.zip', 727 | # '/usr/lib/python3.8', 728 | # '/usr/lib/python3.8/lib-dynload', 729 | # '/home/campos/.local/lib/#python3.8/site-packages', 730 | # '/usr/local/lib/python3.8/dist-packages', 731 | # '/usr/lib/python3/dist-packages'] 732 | ``` 733 | 734 |
735 | 736 | Now, to see where a packeage was imported from you can use the attribute `__file__`: 737 | ```python 738 | import zipp 739 | 740 | zipp.__file__ 741 | # '/usr/lib/python3/dist-packages/zipp.py' 742 | ``` 743 | 744 | > NOTE: you can see that the `__file__` directory is in the list of directories searched by the interpreter. 745 | 746 | 753 | 754 | --- 755 | 756 |
757 | 758 | ## **How Python manages process and threads** 759 | 760 | TODO 761 | 762 | 769 | 770 | --- 771 | 772 |
773 | 774 | ## **How Python manages memory** 775 | 776 | TODO 777 | 778 | 779 | 780 | 781 | --- 782 | 783 |
784 | 785 | ## **How to deeply understand Python code execution** 786 | 787 | 788 | TODO 789 | 790 | 795 | 796 | 797 | --- 798 | 799 |
800 | 801 | ## **Static code analysis** 802 | The static code analysis serves to **evaluate the coding**. This analysis must be done before submitting for a code review. The static code analysis can check: 803 | - Code styling analysis 804 | - Comment styling analysis 805 | - Error detection 806 | - Duplicate code detection 807 | - Unused code detection 808 | - Complexity analysis 809 | - Security linting 810 | 811 | The characteristics of a static analysis are: 812 | - Provides insight into code without executing it 813 | - Can automate code quality maintenance 814 | - Can automate the search for bugs at the early stages 815 | - Can automate the finding of security problems 816 | 817 | A lint, is a [static code analysis tool](https://en.wikipedia.org/wiki/Lint_(software)). 818 | 819 |
820 | Pylint 821 | 822 | [Pylint](https://pylint.org/) is a lint that checks for errors in Python code, tries to enforce a coding standard and looks for code smells. The principal features is: 823 | - Pylint follow the [PEP8](https://www.python.org/dev/peps/pep-0008/) style guide. 824 | - It's possible automate with Jenkins. 825 | - It is fully customizable through a `.pylintrc` file where you can choose which errors or agreements are relevant to you. 826 | - Usage 827 | ```bash 828 | # Get Errors & Warnings 829 | pylint -rn --rcfile=<.pylintrc> 830 | 831 | # Get Full Report 832 | pylint --rcfile=<.pylintrc> 833 | ``` 834 |
835 | Example execution 836 | 837 |
838 |
839 | 840 |
841 |
842 | 843 |
844 | Pyflakes 845 | 846 | [Documentation Pyflakes](https://github.com/PyCQA/pyflakes) 847 |
848 |
849 | 850 |
851 | Mypy 852 | 853 | [Documentation Mypy](http://mypy-lang.org/) 854 |
855 |
856 | 857 |
858 | Prospector 859 | 860 | [Documentation Propector](https://prospector.landscape.io/en/master/) 861 |
862 |
863 | 864 | --- 865 | 866 |
867 | 868 | ## Other Tools to make an effective Python style guide 869 |
870 | Isort 871 | 872 | [isort](https://pypi.org/project/isort/) is a Python tool/library for sorting imports alphabetically, automatically divided into sections. It is very useful in projects where we deal with a lot of imports [6]. 873 | ```bash 874 | # sort the whole project 875 | isort --recursive ./src/ 876 | 877 | # just check for errors 878 | isort script.py --check-only 879 | ``` 880 |
881 |
882 | 883 |
884 | Unify 885 | 886 | Someone likes to write them in single quotes, someone in double ones. To unify the whole project, there is a tool that allows you to automatically align with your style guide — [unify](https://pypi.python.org/pypi/unify) [6]. 887 | ```bash 888 | unify --in-place -r ./src/ 889 | ``` 890 | Work recursively for files in the folder. 891 | 892 |
893 |
894 | 895 |
896 | docformatter 897 | 898 | [Docformater](https://pypi.org/project/docformatter/) is utility helps to bring your docstring under the [PEP 257](https://www.python.org/dev/peps/pep-0257/) [6]. The agreement specifies how documentation should be written. 899 | ```bash 900 | docformatter --in-place example.py 901 | ``` 902 | 903 |
904 |
905 | 906 |
907 | Autoformatters 908 | 909 | There are also automatic code formatters now, here are the popular one [6]: 910 | - [yapf](https://github.com/google/yapf) (here you can make a align with your own style guide) 911 | - [black](https://github.com/psf/black) (you don't need a style guide because you don't have a choice) 912 | - [autopep8](https://github.com/hhatto/autopep8) (makes your python script to conform PEP8 style guide) 913 | 914 |
915 |
916 | 917 |
918 | Settings files to text editor and IDE 919 | 920 | - EditorConfig 921 | - Gitattributes 922 | 923 |
924 |
925 | 926 | --- 927 | 928 |
929 | 930 | ## **Principal style guides** 931 | To make the code consistent and make sure it's readable the _style guides_ can help. 932 | - [Google style guide: THE BETTER](https://google.github.io/styleguide/pyguide.html) 933 | - [Real Python: Naming Conventions](https://realpython.com/python-pep8/#naming-conventions) 934 | - [PEP 08: Style Guide](https://www.python.org/dev/peps/pep-0008/) 935 | - [PEP 257: Docstrings](https://www.python.org/dev/peps/pep-0257/) 936 | - [PEP 484: Type Hints](https://www.python.org/dev/peps/pep-0484/) 937 | 938 | --- 939 | 940 |
941 | 942 | ## **My Knobs** 943 | 944 |
945 | Identation and Length 946 | 947 | - 4 spaces 948 | - Limit all lines to a maximum **72 characteres to docstring or comments** 949 | - Limit all lines to a maximum **79 characteres to code** 950 |
951 |
952 | 953 |
954 | Naming Convention 955 | 956 | - Class Name (camelCase): `CapWords()` 957 | - Variables (snack_case): `cat_words` 958 | - Constants: `MAX_OVERFLOW` 959 |
960 |
961 | 962 | 963 |
964 | Exception 965 | 966 | Limit the clausule `try:` minimal code necessary. 967 | 968 | Yes: 969 | ```Python 970 | try: 971 | value = collection[key] 972 | except KeyError: 973 | return key_not_found(key) 974 | else: 975 | return handle_value(value) 976 | ``` 977 | 978 | No: 979 | ```Python 980 | try: 981 | # Too broad! 982 | return handle_value(collection[key]) 983 | except KeyError: 984 | # Will also catch KeyError raised by handle_value() 985 | return key_not_found(key) 986 | ``` 987 | 988 | - The goal to answer the question **"What went wrong?"** programmatically rather than just claiming that _"There was a problem"_ 989 |
990 |
991 | 992 |
993 | Return 994 | 995 | "_Should explicitly state this as return None_" 996 | 997 | - Be consistent in return statements. 998 | - Todas as instruções de retorno em uma função devem retornar uma expressão ou nenhuma delas deve. 999 | 1000 | Yes: 1001 | ```Python 1002 | def foo(x): 1003 | if x >= 0: 1004 | return math.sqrt(x) 1005 | else: 1006 | return None 1007 | ``` 1008 | 1009 | No: 1010 | ```Python 1011 | def foo(x): 1012 | if x >= 0: 1013 | return math.sqrt(x) 1014 | ``` 1015 |
1016 |
1017 | 1018 | --- 1019 | 1020 |
1021 | 1022 | ## **Docstrings** 1023 | 1024 | Docstrings must have: 1025 | - Args 1026 | - Returns 1027 | - Raises 1028 | 1029 | 1030 |
1031 | Example Google Style Guide 1032 | 1033 | ```Python 1034 | def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): 1035 | """Fetches rows from a Bigtable. 1036 | 1037 | Retrieves rows pertaining to the given keys from the Table instance 1038 | represented by big_table. Silly things may happen if 1039 | other_silly_variable is not None. 1040 | 1041 | Args: 1042 | big_table: An open Bigtable Table instance. 1043 | keys: A sequence of strings representing the key of each table row 1044 | to fetch. 1045 | other_silly_variable: Another optional variable, that has a much 1046 | longer name than the other args, and which does nothing. 1047 | 1048 | Returns: 1049 | A dict mapping keys to the corresponding table row data 1050 | fetched. Each row is represented as a tuple of strings. For 1051 | example: 1052 | 1053 | {'Serak': ('Rigel VII', 'Preparer'), 1054 | 'Zim': ('Irk', 'Invader'), 1055 | 'Lrrr': ('Omicron Persei 8', 'Emperor')} 1056 | 1057 | If a key from the keys argument is missing from the dictionary, 1058 | then that row was not found in the table. 1059 | 1060 | Raises: 1061 | IOError: An error occurred accessing the bigtable.Table object. 1062 | """ 1063 | return None 1064 | ``` 1065 |
1066 |
1067 | 1068 | 1069 | 1072 | 1073 | --- 1074 | 1075 |
1076 | 1077 |
1078 | References 1079 | 1080 | - 1: [Python 3 Installation & Setup Guide](https://realpython.com/installing-python/) 1081 | - 2: [An Effective Python Environment: Making Yourself at Home](https://realpython.com/effective-python-environment/) 1082 | - 3: [Import Scripts as Modules](https://realpython.com/python-import/#import-scripts-as-modules) 1083 | - 4: [Python Modules and Packages – An Introduction](https://realpython.com/python-modules-packages/) 1084 | - 5: [What Is the Python Global Interpreter Lock (GIL)?](https://realpython.com/python-gil/) 1085 | - 6: [7 tips to make an effective python style guide](https://luminousmen.com/post/7-tips-to-make-an-effective-python-style-guide) 1086 | - 7: [Python Static Analysis Tools](https://luminousmen.com/post/python-static-analysis-tools) 1087 | - 8: [My unpopular opinion about black code formatter](https://luminousmen.com/post/my-unpopular-opinion-about-black-code-formatter) 1088 |
1089 |
1090 | 1091 | --- 1092 | 1093 |

1094 |
1095 | 1096 | 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | Creative Commons License 1105 | 1106 |
1107 |

1108 | -------------------------------------------------------------------------------- /config_files/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/config_files/__init__.py -------------------------------------------------------------------------------- /config_files/bkp_readme.md: -------------------------------------------------------------------------------- 1 | # Becoming a Expert Python 2 | ![License](https://img.shields.io/badge/Code%20License-MIT-blue.svg) 3 | ![Python 3](https://img.shields.io/badge/python-3-yellow.svg) 4 | 5 | 6 | 7 | 8 | These guides aim to understand the development and execution environment of Python. In addition, I will cover topics ranging from language fundamentals, good practices, build, deploy, distribution to advanced language programming topics. 9 | 10 | _Estes guias tem por objetivo compreender o ambiente de desenvolvimento e execução de Python. Além disso, vou cobrir tópicos que envolvem desde os fundamentos da linguagem, boas práticas, build, deploy e distribuição_ 11 | 12 | - NOTE: Tópicos avançados de programação com Python ficaram em outro contexto. 13 | 14 | # Summary 15 | [ How to install and set up a Python](#how-to-install-and-set-up-a-Python) 16 | 17 | ## Preparing the Environment for the Python 18 | This topic describe how to set up the environment to Python developement. 19 | - [Check Python Configuration](#check-python-configuration) 20 | - [Preparing Environment](#preparing-environment) 21 | - [Requirements File](#requirements-file) 22 | - [Virtual Environment](#virtual-environment) 23 | - [Pipenv](#pipenv) 24 | 25 | ## Fundamentals 26 | - [What's is Python ?](#what's-is-python-?) 27 | - [Zen of Python](#zen-of-python) 28 | - [Types](#types) 29 | - [Interpreter and Compiler](#interpreter-and-compiler) 30 | - [Complete Documentation](#https://docs.python.org/3/contents.html) 31 | - [Main()](#main()) 32 | - [__ main __](#main) 33 | 38 | - [Executing modules as scripts](#) 39 | - [Options Command](#) 40 | - [`-c` command](#) 41 | 42 | - Language limitations 43 | - GIL 44 | - Python Files 45 | - [.py](#Files:-.) 46 | - [.pyc](#Files:-.) 47 | - [.pyo](#Files:-.) 48 | - [.egg](#Files:-.) 49 | - [`__init__.py`](#_init.py) 50 | - [`__main__.py`](#_main.py) 51 | - [Requirements File](#requirements-file) 52 | - [Pipfile and Pipfile.lock](#pipfile-and-pipfile.lock) 53 | 54 | 68 | 69 | 267 | 268 | ## Files 269 | - o arquivo de saída padrão pode ser referenciado como `sys.stdout` 270 | 271 | ## Serialization 272 | - Pickle 273 | - sqlite 274 | 275 | ## Classes 276 | - Um namespace é um mapeamento de nomes para objetos. 277 | apenas ligam nomes a objetos 278 | - verbos para métodos e substantivos para atributos de dados 279 | - nada no Python torna possível impor a ocultação de dados 280 | 281 | Examples: 282 | ```python 283 | class MyClass: 284 | """A simple example class""" 285 | i = 12345 286 | 287 | def f(self): 288 | return 'hello world' 289 | ``` 290 | ##### self 291 | - O primeiro argumento de um método é chamado self. Isso nada mais é do que uma convenção 292 | - É útil para aumenta a legibilidade dos métodos: não há chance de confundir variáveis ​​locais e variáveis ​​de instância ao olhar através de um método. 293 | 294 | ```python 295 | class Bag: 296 | def __init__(self): 297 | self.data = [] 298 | 299 | def add(self, x): 300 | self.data.append(x) 301 | 302 | def addtwice(self, x): 303 | self.add(x) 304 | self.add(x) 305 | ``` 306 | 307 | ##### `__class__` 308 | - Each value is an object. It is stored as `object.__class__` 309 | 310 | ```python 311 | class MyFirstClass: 312 | """A simple example class""" 313 | i = 42 314 | 315 | def func_ex(self): 316 | print('learning Python') 317 | 318 | 319 | if __name__ == '__main__': 320 | object = MyFirstClass() # initialized instance 321 | object.func_ex() 322 | 323 | print(object.__class__) 324 | 325 | # learning Python 326 | # 327 | ``` 328 | 329 | 402 | 403 | --- 404 | 405 | 406 | ## References 407 | - https://realpython.com/python-virtual-environments-a-primer/ 408 | - https://github.com/vinta/awesome-python/edit/master/README.md 409 | - https://www.digitalocean.com/community/tutorials/how-to-install-python-3-and-set-up-a-programming-environment-on-ubuntu-18-04-quickstart 410 | - https://jtemporal.com/requirements-txt/ 411 | - https://pip.pypa.io/en/stable/user_guide/ 412 | 413 | --- 414 | 415 |

416 |
417 | Gmail 418 | 419 | GitHub 420 | 421 | LinkedIn 422 | GitHub 423 | Website 424 | 425 | GitHub 426 | 427 | Creative Commons License
428 |

429 | -------------------------------------------------------------------------------- /config_files/config_by_environment/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/config_files/config_by_environment/__init__.py -------------------------------------------------------------------------------- /config_files/config_by_environment/config.py: -------------------------------------------------------------------------------- 1 | class Config: 2 | APP_NAME = 'myapp' 3 | SECRET_KEY = 'secret-key-of-myapp' 4 | ADMIN_NAME = 'administrator' 5 | 6 | AWS_DEFAULT_REGION = 'ap-northeast-2' 7 | 8 | STATIC_PREFIX_PATH = 'static' 9 | 10 | class DevelopmentConfig(Config): 11 | DEBUG = True 12 | 13 | AWS_ACCESS_KEY_ID = 'aws-access-key-for-dev' 14 | AWS_SECERT_ACCESS_KEY = 'aws-secret-access-key-for-dev' 15 | AWS_S3_BUCKET_NAME = 'aws-s3-bucket-name-for-dev' 16 | 17 | 18 | class TestConfig(Config): 19 | DEBUG = True 20 | TESTING = True 21 | 22 | AWS_ACCESS_KEY_ID = 'aws-access-key-for-test' 23 | AWS_SECERT_ACCESS_KEY = 'aws-secret-access-key-for-test' 24 | AWS_S3_BUCKET_NAME = 'aws-s3-bucket-name-for-test' 25 | 26 | 27 | class ProductionConfig(Config): 28 | DEBUG = False 29 | 30 | AWS_ACCESS_KEY_ID = 'aws-access-key-for-prod' 31 | AWS_SECERT_ACCESS_KEY = 'aws-secret-access-key-for-prod' 32 | AWS_S3_BUCKET_NAME = 'aws-s3-bucket-name-for-prod' 33 | -------------------------------------------------------------------------------- /config_files/config_by_environment/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | from bottle import app 4 | 5 | from configuration_files.configuration_by_environment import config 6 | 7 | if __name__ == '__main__': 8 | env = sys.argv[1] if len(sys.argv) > 2 else 'dev' 9 | 10 | if env == 'dev': 11 | app.config = config.DevelopmentConfig 12 | 13 | elif env == 'test': 14 | app.config = config.TestConfig 15 | elif env == 'prod': 16 | print('Select: production') 17 | app.config = config.ProductionConfig 18 | 19 | else: 20 | raise ValueError('Invalid environment name') 21 | 22 | app.ci = config.CIConfig 23 | -------------------------------------------------------------------------------- /config_files/dynamic_loading/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/config_files/dynamic_loading/__init__.py -------------------------------------------------------------------------------- /config_files/dynamic_loading/config.py: -------------------------------------------------------------------------------- 1 | DATABASE_CONFIG = { 2 | 'host': 'TEST', 3 | 'dbname': 'company', 4 | 'user': 'user', 5 | 'password': 'password', 6 | 'port': 3306 7 | } -------------------------------------------------------------------------------- /config_files/dynamic_loading/main.py: -------------------------------------------------------------------------------- 1 | import pymysql 2 | import config 3 | import os 4 | 5 | 6 | BASE_DIR = os.path.abspath(os.path.dirname(__file__)) 7 | 8 | 9 | def connect_db(dbname): 10 | if dbname != config.DATABASE_CONFIG['dbname']: 11 | raise ValueError("Couldn't not find DB with given name") 12 | 13 | conn = pymysql.connect(host=config.DATABASE_CONFIG['host'], 14 | user=config.DATABASE_CONFIG['user'], 15 | password=config.DATABASE_CONFIG['password'], 16 | db=config.DATABASE_CONFIG['dbname']) 17 | return conn 18 | 19 | 20 | print(BASE_DIR) 21 | connect_db('company') 22 | -------------------------------------------------------------------------------- /config_files/dynamic_loading/setting/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/config_files/dynamic_loading/setting/__init__.py -------------------------------------------------------------------------------- /config_files/dynamic_loading/setting/config.py: -------------------------------------------------------------------------------- 1 | DATABASE_CONFIG = { 2 | 'host': 'TESTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTT', 3 | 'dbname': 'company', 4 | 'user': 'user', 5 | 'password': 'password', 6 | 'port': 3306 7 | } -------------------------------------------------------------------------------- /config_files/external_config_file/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/config_files/external_config_file/__init__.py -------------------------------------------------------------------------------- /config_files/external_config_file/config.ini: -------------------------------------------------------------------------------- 1 | [DEFAULT] 2 | SECRET_KEY = secret-key-of-myapp 3 | ADMIN_NAME = administrator 4 | AWS_DEFAULT_REGION = ap-northeast-2 5 | MAX_IMAGE_SIZE = 5242880 6 | 7 | [TEST] 8 | TEST_TMP_DIR = tests 9 | TEST_TIMEOUT = 20 10 | 11 | [CI] 12 | SERVICE = travis-ci 13 | HOOK_URL = web-hooking-url-from-ci-service -------------------------------------------------------------------------------- /config_files/external_config_file/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "DEFAULT": { 3 | "SECRET_KEY": "secret-key-of-myapp", 4 | "ADMIN_NAME": "administrator", 5 | "AWS_DEFAULT_REGION": "ap-northeast-2", 6 | "MAX_IMAGE_SIZE": 5242880 7 | }, 8 | "TEST": { 9 | "TEST_TMP_DIR": "tests", 10 | "TEST_TIMEOUT": 20 11 | }, 12 | "CI": { 13 | "SERVICE": "travis-ci", 14 | "HOOK_URL": "web-hooking-url-from-ci-service" 15 | } 16 | } -------------------------------------------------------------------------------- /config_files/external_config_file/main_with_ini.py: -------------------------------------------------------------------------------- 1 | import configparser 2 | 3 | config = configparser.ConfigParser() 4 | config.read('config.ini') 5 | 6 | secret_key = config['DEFAULT']['SECRET_KEY'] # 'secret-key-of-myapp' 7 | ci_hook_url = config['CI']['HOOK_URL'] # 'web-hooking-url-from-ci-service' 8 | 9 | # other form 10 | secret_key = config.get("DEFAULT", "SECRET_KEY") 11 | ci_hook_url = config.get('CI', 'HOOK_URL') 12 | -------------------------------------------------------------------------------- /config_files/external_config_file/main_with_json.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | with open('config.json', 'r') as f: 4 | config = json.load(f) 5 | 6 | secret_key = config['DEFAULT']['SECRET_KEY'] # 'secret-key-of-myapp' 7 | ci_hook_url = config['CI']['HOOK_URL'] # 'web-hooking-url-from-ci-service' -------------------------------------------------------------------------------- /config_files/main_with_env.py: -------------------------------------------------------------------------------- 1 | import os 2 | from myapp import app 3 | 4 | secret_key = os.environ.get('SECRET_KEY', None) 5 | 6 | if not secret_key: 7 | raise ValueError('You must have "SECRET_KEY" variable') 8 | 9 | app.config['SECRET_KEY'] = secret_key 10 | 11 | # The configuration values are not managed as a separate file, so there is less risk of exposure of secret values 12 | -------------------------------------------------------------------------------- /docs/seminario_python-pt-br.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/docs/seminario_python-pt-br.pdf -------------------------------------------------------------------------------- /environment/container/.dockerignore: -------------------------------------------------------------------------------- 1 | ### Python template 2 | # Byte-compiled / optimized / DLL files 3 | __pycache__/ 4 | *.py[cod] 5 | *$py.class 6 | 7 | # C extensions 8 | *.so 9 | 10 | # Distribution / packaging 11 | .Python 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *.cover 48 | .hypothesis/ 49 | .pytest_cache/ 50 | 51 | # Translations 52 | *.mo 53 | *.pot 54 | 55 | # Django stuff: 56 | *.log 57 | local_settings.py 58 | db.sqlite3 59 | 60 | # Flask stuff: 61 | instance/ 62 | .webassets-cache 63 | 64 | # Scrapy stuff: 65 | .scrapy 66 | 67 | # Sphinx documentation 68 | docs/_build/ 69 | 70 | # PyBuilder 71 | target/ 72 | 73 | # Jupyter Notebook 74 | .ipynb_checkpoints 75 | 76 | # pyenv 77 | .python-version 78 | 79 | # celery beat schedule file 80 | celerybeat-schedule 81 | 82 | # SageMath parsed files 83 | *.sage.py 84 | 85 | # Environments 86 | .env 87 | .venv 88 | env/ 89 | venv/ 90 | ENV/ 91 | env.bak/ 92 | venv.bak/ 93 | 94 | # Spyder project settings 95 | .spyderproject 96 | .spyproject 97 | 98 | # Rope project settings 99 | .ropeproject 100 | 101 | # mkdocs documentation 102 | /site 103 | 104 | # mypy 105 | .mypy_cache/ 106 | 107 | 108 | ### Linux template 109 | *~ 110 | 111 | # temporary files which can be created if a process still has a handle open of a deleted file 112 | .fuse_hidden* 113 | 114 | # KDE directory preferences 115 | .directory 116 | 117 | # Linux trash folder which might appear on any partition or disk 118 | .Trash-* 119 | 120 | # .nfs files are created when an open file is removed but is still being accessed 121 | .nfs* 122 | 123 | 124 | ### VirtualEnv template 125 | # Virtualenv 126 | # http://iamzed.com/2009/05/07/a-primer-on-virtualenv/ 127 | .Python 128 | [Bb]in 129 | [Ii]nclude 130 | [Ll]ib 131 | [Ll]ib64 132 | [Ll]ocal 133 | [Ss]cripts 134 | pyvenv.cfg 135 | .venv 136 | pip-selfcheck.json 137 | 138 | 139 | ### JetBrains template 140 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 141 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 142 | 143 | # User-specific stuff 144 | .idea/**/workspace.xml 145 | .idea/**/tasks.xml 146 | .idea/**/dictionaries 147 | .idea/**/shelf 148 | 149 | # Sensitive or high-churn files 150 | .idea/**/dataSources/ 151 | .idea/**/dataSources.ids 152 | .idea/**/dataSources.local.xml 153 | .idea/**/sqlDataSources.xml 154 | .idea/**/dynamic.xml 155 | .idea/**/uiDesigner.xml 156 | .idea/**/dbnavigator.xml 157 | 158 | # Gradle 159 | .idea/**/gradle.xml 160 | .idea/**/libraries 161 | 162 | # CMake 163 | cmake-build-debug/ 164 | cmake-build-release/ 165 | 166 | # Mongo Explorer plugin 167 | .idea/**/mongoSettings.xml 168 | 169 | # File-based project format 170 | *.iws 171 | 172 | # IntelliJ 173 | out/ 174 | 175 | # mpeltonen/sbt-idea plugin 176 | .idea_modules/ 177 | 178 | # JIRA plugin 179 | atlassian-ide-plugin.xml 180 | 181 | # Cursive Clojure plugin 182 | .idea/replstate.xml 183 | 184 | # Crashlytics plugin (for Android Studio and IntelliJ) 185 | com_crashlytics_export_strings.xml 186 | crashlytics.properties 187 | crashlytics-build.properties 188 | fabric.properties 189 | 190 | # Editor-based Rest Client 191 | .idea/httpRequests 192 | 193 | ### VisualStudioCode template 194 | .vscode/* 195 | !.vscode/settings.json 196 | !.vscode/tasks.json 197 | !.vscode/launch.json 198 | !.vscode/extensions.json 199 | 200 | 201 | # Git 202 | .git/ 203 | .gitignore 204 | 205 | # Dockerfile 206 | Dockerfile 207 | .dockerignore 208 | -------------------------------------------------------------------------------- /environment/container/Dockerfile: -------------------------------------------------------------------------------- 1 | # Set the base image 2 | FROM python:3 3 | 4 | # Set environment variables 5 | ENV LANG=C.UTF-8 LC_ALL=C.UTF-8 6 | 7 | # COPY, best pratices: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/ 8 | RUN mkdir /usr/src/app 9 | COPY ./ ./usr/src/app 10 | RUN cd usr/src/app && ls -la 11 | 12 | # Update and 13 | RUN apt-get update && apt-get -yq dist-upgrade 14 | 15 | # Installs 16 | RUN apt-get install -y git \ 17 | vim \ 18 | tree \ 19 | wget \ 20 | && pip install --no-cache-dir -r usr/src/app/src/environment/requirements.txt 21 | 22 | # Clean 23 | RUN apt autoclean \ 24 | && rm -rf /var/lib/apt/lists/* 25 | 26 | # Set config jupyter 27 | RUN mkdir $HOME/.jupyter/ 28 | RUN mv usr/src/app/src/environment/jupyter_notebook_config.py $HOME/.jupyter/ 29 | 30 | # Set working directory 31 | WORKDIR /usr/src/app 32 | 33 | # Run shell command for notebook on start 34 | CMD jupyter notebook --ip 0.0.0.0 --no-browser --allow-root 35 | -------------------------------------------------------------------------------- /environment/create_requirements_from_notebook.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Description: Create file with requirements 3 | # Author: brunocampos01 4 | # Input: N/A 5 | # Output: requirements.txt 6 | # ----------------------------------- # 7 | PROJECT_DIR="$(dirname $(readlink -f $0))" 8 | 9 | rm -f requirements.txt 10 | touch requirements.txt 11 | 12 | # Convert files .ipynb to python 13 | jupyter nbconvert --to python notebooks/*.ipynb 14 | 15 | # Generate requirements 16 | pipreqs notebooks/ --force --savepath requirements.txt 17 | 18 | # Remove converted files 19 | rm -rf notebooks/*.py 20 | 21 | # Show requirements 22 | echo -e "Requirements this project:\n" 23 | cat requirements.txt 24 | -------------------------------------------------------------------------------- /environment/how-prepare-python-env-in-anywhere.md: -------------------------------------------------------------------------------- 1 | # How prepare Python environment in anywhere 2 | 1. [Local](#running-in-local) 3 | 2. [Development: Virtual Environment](#running-in-virtual-environment) 4 | 3. [Deploy: Container](#running-in-container) 5 | 6 | ## Running in Local 7 | Install Python dependencies, test Python environment and delete all compiled Python files. 8 | 9 | ```shell script 10 | sudo make 11 | 12 | # Available rules: 13 | 14 | # clean Delete all compiled Python files 15 | # install_dependencies Install Python Dependencies 16 | # test_environment Test python environment is setup correctly 17 | ``` 18 | 19 | ```shell script 20 | make install_dependencies 21 | make test_environment 22 | make clean 23 | ``` 24 | 25 | --- 26 | 27 | ## Running in Virtual Environment 28 | 1. Create virtual environment 29 | ```shell script 30 | virtualenv -p python3 venv 31 | ``` 32 | 33 | 2. Activate this semi-isolated environment 34 | ```shell script 35 | source venv/bin/activate 36 | ``` 37 | 38 | 3. Install the libraries 39 | ```shell script 40 | pip3 install -r requirements.txt 41 | ``` 42 | 43 | --- 44 | 45 | ## Running in Container 46 | It's necessary be in project's home 47 | ```sh 48 | name_project=$(basename "$(pwd)") 49 | echo $name_project 50 | sudo docker build --no-cache -t $name_project -f src/environment/container/Dockerfile . 51 | sudo docker run -it -p 8888:8888 $name_project 52 | ``` 53 | -------------------------------------------------------------------------------- /environment/jupyter_notebook_config.py: -------------------------------------------------------------------------------- 1 | c.NotebookApp.ip = '0.0.0.0' 2 | 3 | # The port the notebook server will listen on 4 | c.NotebookApp.port = 8888 5 | 6 | # Whether to open in a browser after starting 7 | c.NotebookApp.open_browser = False 8 | 9 | # Set the Access-Control-Allow-Credentials: true header 10 | c.NotebookApp.allow_password_change = False 11 | 12 | # https://github.com/jupyter/notebook/issues/3130 13 | c.FileContentsManager.delete_to_trash = False 14 | -------------------------------------------------------------------------------- /environment/makefile: -------------------------------------------------------------------------------- 1 | # Description: Install Python dependencies, delete all compiled Python files 2 | # and test python environment 3 | # Author: brunocampos01 4 | # ----------------------------------- # 5 | 6 | .PHONY: clean data install_dependencies 7 | ################################################################################# 8 | # GLOBALS # 9 | ################################################################################# 10 | 11 | PROJECT_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) 12 | PROFILE = default 13 | PROJECT_NAME = PROJECT_DIR 14 | PYTHON_INTERPRETER = python3 15 | 16 | ################################################################################# 17 | # COMMANDS # 18 | ################################################################################# 19 | 20 | ## Install Python Dependencies 21 | install_dependencies: 22 | $ sudo apt install python3 23 | $ sudo apt install build-essential \ 24 | software-properties-common \ 25 | libssl-dev \ 26 | libffi-dev \ 27 | python3-dev \ 28 | python3-venv \ 29 | python3-pip \ 30 | python3-setuptools \ 31 | python3-pkg-resources 32 | $(PYTHON_INTERPRETER) -m pip install -U pip setuptools wheel virtualenv 33 | 34 | ## Delete all compiled Python files 35 | clean: 36 | rm -fr build/ 37 | rm -fr dist/ 38 | rm -fr .eggs/ 39 | rm -fr .ipynb_checkpoints/ 40 | find . -type f -name "*.py[co]" -delete 41 | find . -type d -name "__pycache__" -delete 42 | 43 | ## Test python environment is setup correctly 44 | test_environment: 45 | $(PYTHON_INTERPRETER) test_environment.py 46 | 47 | ################################################################################# 48 | # Self Documenting Commands # 49 | ################################################################################# 50 | 51 | .DEFAULT_GOAL := help 52 | 53 | # Inspired by 54 | # sed script explained: 55 | # /^##/: 56 | # * save line in hold space 57 | # * purge line 58 | # * Loop: 59 | # * append newline + line to hold space 60 | # * go to next line 61 | # * if line starts with doc comment, strip comment character off and loop 62 | # * remove target prerequisites 63 | # * append hold space (+ newline) to line 64 | # * replace newline plus comments by `---` 65 | # * print line 66 | # Separate expressions are necessary because labels cannot be delimited by 67 | # semicolon; see 68 | .PHONY: help 69 | help: 70 | @echo "$$(tput bold)Available rules:$$(tput sgr0)" 71 | @echo 72 | @sed -n -e "/^## / { \ 73 | h; \ 74 | s/.*//; \ 75 | :doc" \ 76 | -e "H; \ 77 | n; \ 78 | s/^## //; \ 79 | t doc" \ 80 | -e "s/:.*//; \ 81 | G; \ 82 | s/\\n## /---/; \ 83 | s/\\n/ /g; \ 84 | p; \ 85 | }" ${MAKEFILE_LIST} \ 86 | | LC_ALL='C' sort --ignore-case \ 87 | | awk -F '---' \ 88 | -v ncol=$$(tput cols) \ 89 | -v indent=19 \ 90 | -v col_on="$$(tput setaf 6)" \ 91 | -v col_off="$$(tput sgr0)" \ 92 | '{ \ 93 | printf "%s%*s%s ", col_on, -indent, $$1, col_off; \ 94 | n = split($$2, words, " "); \ 95 | line_length = ncol - indent; \ 96 | for (i = 1; i <= n; i++) { \ 97 | line_length -= length(words[i]) + 1; \ 98 | if (line_length <= 0) { \ 99 | line_length = ncol - indent - length(words[i]) - 1; \ 100 | printf "\n%*s ", -indent, " "; \ 101 | } \ 102 | printf "%s ", words[i]; \ 103 | } \ 104 | printf "\n"; \ 105 | }' \ 106 | | more $(shell test $(shell uname) = Darwin && echo '--no-init --raw-control-chars') 107 | -------------------------------------------------------------------------------- /environment/test_environment.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | REQUIRED_PYTHON = "python3" 4 | 5 | 6 | def check_python_version(python_req: str): 7 | # major = 3 8 | system_major = sys.version_info.major 9 | 10 | if python_req == "python": 11 | required_major = 2 12 | elif python_req == "python3": 13 | required_major = 3 14 | else: 15 | raise ValueError("Unrecognized python interpreter: {}" 16 | .format(python_req)) 17 | 18 | if system_major != required_major: 19 | raise TypeError("This project requires Python {}. Found: Python {}" 20 | .format(required_major, sys.version)) 21 | else: 22 | print("Python Version: {}".format(sys.version)) # e.g 3.11 23 | print("Development environment passes all tests!") 24 | 25 | 26 | def main(): 27 | check_python_version(python_req = REQUIRED_PYTHON) 28 | 29 | 30 | if __name__ == "__main__": 31 | main() 32 | -------------------------------------------------------------------------------- /example_imports/cli.py: -------------------------------------------------------------------------------- 1 | from structure.structure import main 2 | 3 | if __name__ == "__main__": 4 | main() 5 | -------------------------------------------------------------------------------- /example_imports/data/test.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/example_imports/data/test.xml -------------------------------------------------------------------------------- /example_imports/structure/files.py: -------------------------------------------------------------------------------- 1 | def unique_path(directory, name_pattern): 2 | """Find a path name that does not already exist""" 3 | counter = 0 4 | while True: 5 | counter += 1 6 | path = directory / name_pattern.format(counter) 7 | if not path.exists(): 8 | return path 9 | 10 | 11 | def add_empty_file(path): 12 | """Create an empty file at the given path""" 13 | print(f"Create file: {path}") 14 | path.parent.mkdir(parents=True, exist_ok=True) 15 | path.touch() 16 | -------------------------------------------------------------------------------- /example_imports/structure/structure.py: -------------------------------------------------------------------------------- 1 | # Standard library imports 2 | import pathlib 3 | import sys 4 | 5 | # ---------------------------------------------------------------------------- 6 | # Local imports 7 | # ---------------------------------------------------------------------------- 8 | 9 | # # option: 1 10 | # import files 11 | 12 | # option: 2 13 | # Implicit Relative Imports. 14 | # These were removed from the language by PEP 328 15 | # The issue with this approach is that your 16 | # import path can get very messy and hard to understand. 17 | sys.path.insert(0, str(pathlib.Path(__file__).parent)) 18 | import files 19 | 20 | # option: 3 21 | # from . import files 22 | 23 | # A more common way to open data files 24 | # is to locate them based on your module’s __file__ attribute: 25 | import pathlib 26 | 27 | DATA_DIR = f'{pathlib.Path(__file__).parent.parent}/data' 28 | with open(f'{DATA_DIR}/test.xml') as fid: 29 | fid.read() 30 | 31 | 32 | def main(): 33 | # Read path from command line 34 | try: 35 | breakpoint() # type n in PDB 36 | root = pathlib.Path(sys.argv[1]).resolve() 37 | except IndexError: 38 | print("Need one argument: the root of the original file tree") 39 | raise SystemExit() 40 | 41 | # Re-create the file structure 42 | new_root = files.unique_path(pathlib.Path.cwd(), "{:03d}") 43 | for path in root.rglob("*"): 44 | if path.is_file() and new_root not in path.parents: 45 | rel_path = path.relative_to(root) 46 | files.add_empty_file(new_root / rel_path) 47 | 48 | 49 | if __name__ == "__main__": 50 | main() 51 | -------------------------------------------------------------------------------- /exercises/find_path/README.md: -------------------------------------------------------------------------------- 1 | # Find all files within a path 2 | 3 | Find all files within a path, with a given file name suffix. Note that a path may contain further 4 | subdirectories and those subdirectories may also contain furthersubdirectories. There is no limit 5 | to the depth of the subdirectories. 6 | Arguments: 7 | suffix(str): suffix if the file name to be found 8 | path(str): path of the file system 9 | Returns: 10 | a list of paths and file names that match the suffix 11 | 12 | Expected deliverable 13 | Your code should be executable with the following call “yourScript.py *.log /var/tmp”. 14 | See below for an example of what the output should be (for a given scenario): 15 | Scenario: 16 | ```commandline 17 | |-- a 18 | | |-- bbb 19 | | |-- bbb.log 20 | | |-- ddd 21 | |-- aaa.log 22 | |-- abc.txt 23 | ``` 24 | 25 | Output: 26 | ``` 27 | ./aaa.log 28 | ./a/bbb.log 29 | ``` 30 | 31 | ## How to Run 32 | ### Requisite 33 | 34 | | Requisite | Version | 35 | | --------- | ------- | 36 | | Python | 3.9.7 | 37 | 38 | ```bash 39 | # application example 40 | python first_exercise/app/find_files.py *.md /home/$USER 41 | 42 | # tests 43 | python -m unittest first_exercise/test/test_find_files.py 44 | ``` 45 | 46 | --- 47 | -------------------------------------------------------------------------------- /exercises/find_path/app/find_files.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | import fnmatch 3 | import os 4 | from typing import List 5 | 6 | 7 | def find_files(suffix: str, path: str) -> List[str]: 8 | """ 9 | Find all files with a given suffix in a path and its subdirectories. 10 | Args: 11 | suffix: The suffix of the files to find. 12 | path: The path to search for files. 13 | Returns: 14 | A list of paths to files with the given suffix. 15 | """ 16 | for entry in os.scandir(path): 17 | if entry.is_file() and fnmatch.fnmatch(entry.name, suffix): 18 | yield entry.path 19 | elif entry.is_dir(): 20 | yield from find_files(suffix, entry.path) 21 | 22 | 23 | if __name__ == "__main__": 24 | parser = argparse.ArgumentParser(description="Find all files with a given suffix in a path and its subdirectories.") 25 | parser.add_argument("suffix", type=str, help="The suffix of the files to find. Example: *.pdf") 26 | parser.add_argument("path", type=str, help="The path to search for files.") 27 | args = parser.parse_args() 28 | 29 | files = find_files(args.suffix, args.path) 30 | for file in files: 31 | print(file) 32 | -------------------------------------------------------------------------------- /exercises/find_path/test/test_find_files.py: -------------------------------------------------------------------------------- 1 | import os 2 | import tempfile 3 | import unittest 4 | 5 | from first_exercise.app.find_files import find_files 6 | 7 | 8 | class TestFindFiles(unittest.TestCase): 9 | def setUp(self): 10 | # Create a temporary directory and some files for testing. 11 | self.tempdir = tempfile.TemporaryDirectory() 12 | self.dirpath = self.tempdir.name 13 | self.filepaths = [ 14 | os.path.join(self.dirpath, "file1.txt"), 15 | os.path.join(self.dirpath, "file2.log"), 16 | os.path.join(self.dirpath, "subdir1", "file3.log"), 17 | os.path.join(self.dirpath, "subdir1", "file4.txt"), 18 | os.path.join(self.dirpath, "subdir2", "file5.log"), 19 | ] 20 | os.makedirs(os.path.join(self.dirpath, "subdir1")) 21 | os.makedirs(os.path.join(self.dirpath, "subdir2")) 22 | for filepath in self.filepaths: 23 | with open(filepath, "w") as f: 24 | f.write("test") 25 | 26 | def tearDown(self): 27 | # Clean up the temporary directory and files. 28 | self.tempdir.cleanup() 29 | 30 | def test_positive(self): 31 | # Test that the function returns the correct file paths for a directory with matching files. 32 | result = list(find_files("*.log", self.dirpath)).sort() 33 | expected = [os.path.join(self.dirpath, "file2.log"), 34 | os.path.join(self.dirpath, "subdir1", "file3.log"), 35 | os.path.join(self.dirpath, "subdir2", "file5.log")].sort() 36 | self.assertEqual(result, expected) 37 | 38 | def test_without_matching(self): 39 | # Test that the function returns an empty list for a directory without matching files. 40 | result = list(find_files("*.pdf", self.dirpath)) 41 | expected = [] 42 | self.assertEqual(result, expected) 43 | 44 | def test_empty_suffix(self): 45 | # Test with empty suffix 46 | result = list(find_files('', './')) 47 | expected = [] 48 | self.assertEqual(result, expected) 49 | 50 | def test_not_found_path(self): 51 | # Test with an invalid path. 52 | with self.assertRaises(FileNotFoundError): 53 | list(find_files(".txt", "/invalid/path")) 54 | 55 | def test_invalid_path(self): 56 | # Test with invalid arguments 57 | with self.assertRaises(OSError): 58 | list(find_files('.txt', 123)) 59 | 60 | 61 | if __name__ == "__main__": 62 | unittest.main() 63 | -------------------------------------------------------------------------------- /exercises/multithreading/README.md: -------------------------------------------------------------------------------- 1 | # Multithreading 2 | 3 | Suppose that you want to simulate a fruit farm: 4 | - Three farmers are collecting fruits from a single tree to a single dirty fruit basket. 5 | - In parallel, three other farmers are getting the fruits from the dirty fruit basket, 6 | cleaning them, and pushing them into the single cleaned fruit basket. 7 | - All the farmers are managing the fruit individually 8 | - The tree has 50 fruits (and only one farmer at one time can pick fruit from the tree) 9 | - Time to collect fruits from the trees into the basket: random(3,6) seconds 10 | - Time to clean the fruits into the cleaned fruit basket: random(2,4) seconds 11 | - The simulation ends when all the fruits from the tree are collected and cleaned. 12 | - The number of fruits in the tree and in the baskets must be logged every second. 13 | 14 | 15 | 16 | ### Expected deliverable 17 | 18 | Your code should be executable with the following call “yourScript.py”, with a similar output log 19 | to the one below: 20 | ```commandline 21 | 2020-12-01 19:02:00 Tree (50 fruits) - dirty basket ( 0 ) - Clean Basket ( 0 ) 22 | 23 | # OR 24 | 25 | 2020-12-01 19:02:00 Tree (50 fruits) - dirty basket ( 0 ) - Clean Basket ( 0 ) – (optional) farmer1 26 | (0) – farmer2 (0) – cleaner1(0) – cleaner2 (0) 27 | ``` 28 | 29 | ## How to Run 30 | ### Requisite 31 | 32 | | Requisite | Version | 33 | | --------- | ------- | 34 | | Python | 3.9.7 | 35 | 36 | ```bash 37 | # application 38 | python second_exercise/app/pick_and_clean_fruit.py 39 | 40 | # tests 41 | python -m unittest second_exercise/test/test_pick_and_clean_fruit.py 42 | ``` 43 | 44 | --- 45 | -------------------------------------------------------------------------------- /exercises/multithreading/app/pick_and_clean_fruit.py: -------------------------------------------------------------------------------- 1 | import random 2 | import threading 3 | import time 4 | 5 | 6 | class Tree: 7 | def __init__(self, fruits): 8 | self.fruits = fruits 9 | self.lock = threading.Lock() 10 | 11 | def pick_fruit(self) -> bool: 12 | """ 13 | Returns: 14 | bool: True if a fruit was picked, 15 | False if there are no more fruits left. 16 | """ 17 | with self.lock: 18 | if self.fruits > 0: 19 | self.fruits -= 1 20 | return True 21 | else: 22 | return False 23 | 24 | 25 | class Basket: 26 | def __init__(self): 27 | self.fruits = 0 28 | self.lock = threading.Lock() 29 | 30 | def add_fruit(self): 31 | with self.lock: 32 | self.fruits += 1 33 | 34 | def remove_fruit(self) -> bool: 35 | """ 36 | Returns: 37 | bool: True if a fruit was removed, 38 | False if the basket is empty. 39 | """ 40 | with self.lock: 41 | if self.fruits > 0: 42 | self.fruits -= 1 43 | return True 44 | else: 45 | return False 46 | 47 | 48 | class Farmer(threading.Thread): 49 | def __init__(self, name, tree, dirty_basket, clean_basket): 50 | """ 51 | Initialize a farmer with the given name and baskets. 52 | 53 | Args: 54 | name (str): The name of the farmer. 55 | tree (Tree): The tree to pick fruit from. 56 | dirty_basket (Basket): The basket to put dirty fruit in. 57 | clean_basket (Basket): The basket to put cleaned fruit in. 58 | """ 59 | super().__init__() 60 | self.name = name 61 | self.tree = tree 62 | self.dirty_basket = dirty_basket 63 | self.clean_basket = clean_basket 64 | self.empty_tree = False 65 | self.time_collect_fruits = random.randint(3, 6) 66 | self.time_clean_fruits = random.randint(2, 4) 67 | 68 | def run(self): 69 | """ 70 | Picks fruit from the tree and adds it to the dirty basket, 71 | then cleans fruit from the dirty basket and adds it to the clean basket. 72 | """ 73 | while not self.empty_tree: 74 | # Pick fruit from tree 75 | time.sleep(self.time_collect_fruits) 76 | if self.tree.pick_fruit(): 77 | self.dirty_basket.add_fruit() 78 | else: 79 | self.empty_tree = True 80 | break 81 | 82 | # Clean fruit and add to clean basket 83 | time.sleep(self.time_clean_fruits) 84 | if self.dirty_basket.remove_fruit(): 85 | self.clean_basket.add_fruit() 86 | else: 87 | break 88 | 89 | 90 | def main(): 91 | tree = Tree(50) 92 | dirty_basket = Basket() 93 | clean_basket = Basket() 94 | 95 | farmers = [ 96 | Farmer("farmer1", tree, dirty_basket, clean_basket), 97 | Farmer("farmer2", tree, dirty_basket, clean_basket), 98 | Farmer("farmer3", tree, dirty_basket, clean_basket), 99 | Farmer("cleaner1", tree, dirty_basket, clean_basket), 100 | Farmer("cleaner2", tree, dirty_basket, clean_basket), 101 | Farmer("cleaner3", tree, dirty_basket, clean_basket), 102 | ] 103 | 104 | # Start the threads 105 | for farmer in farmers: 106 | farmer.start() 107 | 108 | # Run the simulation for as long as there are active threads 109 | while any(farmer.is_alive() for farmer in farmers): 110 | time.sleep(1) 111 | print(f"{time.strftime('%Y-%m-%d %H:%M:%S')} Tree ({tree.fruits} fruits) " 112 | f"- Dirty basket ({dirty_basket.fruits}) " 113 | f"- Clean Basket ({clean_basket.fruits}) ") 114 | 115 | 116 | if __name__ == '__main__': 117 | main() 118 | -------------------------------------------------------------------------------- /exercises/multithreading/flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/exercises/multithreading/flow.png -------------------------------------------------------------------------------- /exercises/multithreading/test/test_pick_and_clean_fruit.py: -------------------------------------------------------------------------------- 1 | import time 2 | import unittest 3 | from typing import List 4 | 5 | from second_exercise.app.pick_and_clean_fruit import ( 6 | Tree, 7 | Basket, 8 | Farmer 9 | ) 10 | 11 | 12 | class TestPickAndCleanFruit(unittest.TestCase): 13 | basket = Basket() 14 | dirty_basket = Basket() 15 | clean_basket = Basket() 16 | 17 | @classmethod 18 | def _generate_farmers(cls, tree) -> List: 19 | return [ 20 | Farmer("farmer1", tree, cls.dirty_basket, cls.clean_basket), 21 | Farmer("farmer2", tree, cls.dirty_basket, cls.clean_basket), 22 | Farmer("farmer3", tree, cls.dirty_basket, cls.clean_basket), 23 | Farmer("cleaner1", tree, cls.dirty_basket, cls.clean_basket), 24 | Farmer("cleaner2", tree, cls.dirty_basket, cls.clean_basket), 25 | Farmer("cleaner3", tree, cls.dirty_basket, cls.clean_basket), 26 | ] 27 | 28 | def test_tree_pick_fruit(self): 29 | tree = Tree(10) 30 | for i in range(10): 31 | self.assertTrue(tree.pick_fruit()) 32 | self.assertFalse(tree.pick_fruit()) 33 | 34 | def test_tree_pick_fruit_empty_tree(self): 35 | tree = Tree(0) 36 | self.assertFalse(tree.pick_fruit()) 37 | 38 | def test_basket_add_fruit(self): 39 | self.basket.fruits = 0 40 | 41 | self.basket.add_fruit() 42 | self.assertEqual(self.basket.fruits, 1) 43 | self.basket.add_fruit() 44 | self.assertEqual(self.basket.fruits, 2) 45 | 46 | def test_basket_remove_fruit(self): 47 | self.basket.fruits = 8 48 | 49 | self.basket.remove_fruit() 50 | self.assertEqual(self.basket.fruits, 7) 51 | 52 | def test_basket_remove_fruit_empty_basket(self): 53 | self.basket.fruits = 0 54 | 55 | self.basket.remove_fruit() 56 | self.assertEqual(self.basket.fruits, 0) 57 | 58 | def test_farm_run(self): 59 | tree = Tree(11) 60 | farmers = self._generate_farmers(tree) 61 | 62 | for farmer in farmers: 63 | farmer.start() 64 | 65 | while any(farmer.is_alive() for farmer in farmers): 66 | time.sleep(0.01) 67 | 68 | self.assertEqual(tree.fruits, 0) 69 | self.assertEqual(self.dirty_basket.fruits, 0) 70 | self.assertEqual(self.clean_basket.fruits, 11) 71 | 72 | def test_farm_run_empty_tree(self): 73 | tree_empty = Tree(0) 74 | self.clean_basket.fruits = 0 75 | farmers = self._generate_farmers(tree_empty) 76 | 77 | for farmer in farmers: 78 | farmer.start() 79 | 80 | while any(farmer.is_alive() for farmer in farmers): 81 | time.sleep(0.01) 82 | 83 | self.assertEqual(tree_empty.fruits, 0) 84 | self.assertEqual(self.dirty_basket.fruits, 0) 85 | self.assertEqual(self.clean_basket.fruits, 0) 86 | 87 | 88 | if __name__ == '__main__': 89 | unittest.main() 90 | -------------------------------------------------------------------------------- /fundamentals/Importing.py: -------------------------------------------------------------------------------- 1 | """ 2 | Import modules from an arbitrary filesystem location 3 | """ 4 | 5 | import sys 6 | sys.path.append("/path/to/directory/containing/your/module") 7 | import mymodule 8 | -------------------------------------------------------------------------------- /fundamentals/class.py: -------------------------------------------------------------------------------- 1 | class MyFirstClass: 2 | """A simple example class""" 3 | i = 42 4 | 5 | def func_ex(self): 6 | print('learning Python') 7 | 8 | 9 | if __name__ == '__main__': 10 | object = MyFirstClass() # initialized instance 11 | object.func_ex() 12 | 13 | print(object.__class__) 14 | -------------------------------------------------------------------------------- /fundamentals/example_stacktrace.py: -------------------------------------------------------------------------------- 1 | import traceback 2 | import sys 3 | 4 | 5 | def func(): 6 | try: 7 | raise SomeError("Something went wrong...") 8 | except: 9 | print('traceback\n') 10 | traceback.print_exc(file=sys.stderr) 11 | 12 | 13 | def func(): 14 | try: 15 | raise NotImplementedError("Something went wrong...") 16 | except Exception as err: 17 | raise ('hummmm ...') from err 18 | 19 | 20 | if __name__ == "__main__": 21 | func() 22 | -------------------------------------------------------------------------------- /fundamentals/how_use_arguments.py: -------------------------------------------------------------------------------- 1 | """ 2 | Reference: https://docs.python.org/3/tutorial/controlflow.html 3 | """ 4 | 5 | 6 | def parrot(voltage, state='a stiff', action='voom', 7 | type='Norwegian Blue'): 8 | """ 9 | Accepts one required argument (voltage) 10 | and three optional arguments (state, action, and type). 11 | 12 | Params 13 | :param voltage: required 14 | :param state: optional 15 | :param action: optional 16 | :param type: optional 17 | """ 18 | print("-- This parrot wouldn't", action, end=' ') 19 | print("if you put", voltage, "volts through it.") 20 | print("-- Lovely plumage, the", type) 21 | print("-- It's", state, "!") 22 | 23 | 24 | if __name__ == '__main__': 25 | parrot(1000) # 1 positional argument 26 | parrot(voltage=1000) # 1 keyword argument 27 | parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments 28 | parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments 29 | parrot('a million', 'bereft of life', 30 | 'jump') # 3 positional arguments 31 | parrot('a thousand', 32 | state='pushing up the daisies') # 1 positional, 1 keyword 33 | 34 | # Invalid 35 | # parrot() # required argument missing 36 | # parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument 37 | # parrot(110, voltage=220) # duplicate value for the same argument 38 | # parrot(actor='John Cleese') # unknown keyword argument 39 | -------------------------------------------------------------------------------- /fundamentals/how_use_docstrings.py: -------------------------------------------------------------------------------- 1 | def fetch_bigtable_rows(big_table, keys, other_silly_variable=None): 2 | """Fetches rows from a Bigtable. 3 | 4 | Retrieves rows pertaining to the given keys from the Table instance 5 | represented by big_table. Silly things may happen if 6 | other_silly_variable is not None. 7 | 8 | Args: 9 | big_table: An open Bigtable Table instance. 10 | keys: A sequence of strings representing the key of each table row 11 | to fetch. 12 | other_silly_variable: Another optional variable, that has a much 13 | longer name than the other args, and which does nothing. 14 | 15 | Returns: 16 | A dict mapping keys to the corresponding table row data 17 | fetched. Each row is represented as a tuple of strings. For 18 | example: 19 | 20 | {'Serak': ('Rigel VII', 'Preparer'), 21 | 'Zim': ('Irk', 'Invader'), 22 | 'Lrrr': ('Omicron Persei 8', 'Emperor')} 23 | 24 | If a key from the keys argument is missing from the dictionary, 25 | then that row was not found in the table. 26 | 27 | Raises: 28 | IOError: An error occurred accessing the bigtable.Table object. 29 | """ 30 | return None 31 | 32 | 33 | print(fetch_bigtable_rows.__doc__) 34 | -------------------------------------------------------------------------------- /fundamentals/how_use_iterators.py: -------------------------------------------------------------------------------- 1 | class Reverse: 2 | """Iterator for looping over a sequence backwards.""" 3 | 4 | def __init__(self, data): 5 | self.data = data 6 | self.index = len(data) 7 | 8 | def __iter__(self): 9 | return self 10 | 11 | def __next__(self): 12 | if self.index == 0: 13 | raise StopIteration 14 | self.index = self.index - 1 15 | return self.data[self.index] 16 | -------------------------------------------------------------------------------- /fundamentals/how_use_unpacking_argument.py: -------------------------------------------------------------------------------- 1 | """ 2 | https://docs.python.org/3/tutorial/controlflow.html 3 | """ 4 | 5 | 6 | def parrot(voltage, state='a stiff', action='voom'): 7 | print("-- This parrot wouldn't", action, end=' ') 8 | print("if you put", voltage, "volts through it.", end=' ') 9 | print("E's", state, "!") 10 | 11 | 12 | d = {"voltage": "four million", 13 | "state": "bleedin' demised", 14 | "action": "VOOM"} 15 | 16 | if __name__ == '__main__': 17 | parrot(**d) 18 | -------------------------------------------------------------------------------- /fundamentals/unpacking_arguments_query.py: -------------------------------------------------------------------------------- 1 | """ 2 | This file is good example when use **context 3 | """ 4 | 5 | 6 | def create_statement(type_metric, **context): 7 | """ 8 | :param type_metric: choose table 9 | :param argv: all metrics to records 10 | :return: statement of INSERT INTO 11 | """ 12 | if type_metric == "jobs": 13 | return "INSERT INTO jobs " \ 14 | "(execution_date, job_name, job_status," \ 15 | " start_time, end_time, execution_time, fk_module) " \ 16 | "VALUES " \ 17 | "('{0}', '{1}', '{2}', '{3}', '{4}', '{5}', '{6}');" \ 18 | .format(context['execution_date'], 19 | context['job_name'], 20 | context['status'], 21 | context['start_time'], 22 | context['end_time'], 23 | context['execution_time'], 24 | context['fk_module']) 25 | else: 26 | return "INSERT INTO modules " \ 27 | "(execution_date, module_name, module_status," \ 28 | " start_time, end_time, execution_time) " \ 29 | "VALUES ('{0}', '{1}', '{2}', '{3}', '{4}', '{5}');" \ 30 | .format(context['execution_date'], 31 | context['module_name'], 32 | context['status'], 33 | context['start_time'], 34 | context['end_time'], 35 | context['execution_time']) 36 | 37 | 38 | if __name__ == '__main__': 39 | create_statement(type_metric='modules', 40 | execution_date='2020-01-01', 41 | module_name='search', 42 | status='SUCESS', 43 | start_time='15:00', 44 | end_time='16:30', 45 | execution_time='1:30') 46 | -------------------------------------------------------------------------------- /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/1.png -------------------------------------------------------------------------------- /images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/2.png -------------------------------------------------------------------------------- /images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/3.png -------------------------------------------------------------------------------- /images/Python3VersionChange.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/Python3VersionChange.jpg -------------------------------------------------------------------------------- /images/Python_3._The_standard_type_hierarchy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/Python_3._The_standard_type_hierarchy.png -------------------------------------------------------------------------------- /images/__doc__.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/__doc__.png -------------------------------------------------------------------------------- /images/array-and-lists.svg: -------------------------------------------------------------------------------- 1 |
0
0
1
[Not supported by viewer]
2
2
3
3
4
4
Pointer
[Not supported by viewer]
Pointer
[Not supported by viewer]
0x0001
0x0001
0x0010
0x0010
0x0011
0x0011
0x0100
0x0100
0x0101
0x0101
 Python Arrays
[Not supported by viewer]
More pointers
More pointers
int
int
Elements of the same type
Elements of the same type
Python Objects
<div>Python Objects</div>
 Python Lists
[Not supported by viewer]
Char
Char
String
String
Function
Function
int
int
-------------------------------------------------------------------------------- /images/bashrc_python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/bashrc_python.png -------------------------------------------------------------------------------- /images/change_python.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/change_python.gif -------------------------------------------------------------------------------- /images/comp-interpreter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/comp-interpreter.png -------------------------------------------------------------------------------- /images/config.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/config.jpg -------------------------------------------------------------------------------- /images/cpython.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/cpython.png -------------------------------------------------------------------------------- /images/create_virtualenv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/create_virtualenv.gif -------------------------------------------------------------------------------- /images/debug.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/debug.gif -------------------------------------------------------------------------------- /images/env.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/env.png -------------------------------------------------------------------------------- /images/freeze.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/freeze.png -------------------------------------------------------------------------------- /images/from.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/from.png -------------------------------------------------------------------------------- /images/git_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/git_logo.png -------------------------------------------------------------------------------- /images/help().png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/help().png -------------------------------------------------------------------------------- /images/icon_ubuntu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/icon_ubuntu.png -------------------------------------------------------------------------------- /images/icon_windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/icon_windows.png -------------------------------------------------------------------------------- /images/icons_test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/icons_test.png -------------------------------------------------------------------------------- /images/import.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/import.png -------------------------------------------------------------------------------- /images/in-production.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/in-production.gif -------------------------------------------------------------------------------- /images/install_python.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/install_python.gif -------------------------------------------------------------------------------- /images/interpreter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/interpreter.png -------------------------------------------------------------------------------- /images/jython.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/jython.jpg -------------------------------------------------------------------------------- /images/list_versions.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/list_versions.gif -------------------------------------------------------------------------------- /images/multithread.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/multithread.png -------------------------------------------------------------------------------- /images/operadores.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/operadores.png -------------------------------------------------------------------------------- /images/org_python.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/org_python.jpg -------------------------------------------------------------------------------- /images/org_python_virtualenv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/org_python_virtualenv.jpg -------------------------------------------------------------------------------- /images/pipe.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/pipe.gif -------------------------------------------------------------------------------- /images/pipenv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/pipenv.gif -------------------------------------------------------------------------------- /images/pipenv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/pipenv.png -------------------------------------------------------------------------------- /images/pipenv_lock.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/pipenv_lock.gif -------------------------------------------------------------------------------- /images/precedencia.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/precedencia.png -------------------------------------------------------------------------------- /images/pylint_example.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/pylint_example.gif -------------------------------------------------------------------------------- /images/python.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python.png -------------------------------------------------------------------------------- /images/python_1.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_1.PNG -------------------------------------------------------------------------------- /images/python_2.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_2.PNG -------------------------------------------------------------------------------- /images/python_3.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_3.PNG -------------------------------------------------------------------------------- /images/python_4.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_4.PNG -------------------------------------------------------------------------------- /images/python_5.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_5.PNG -------------------------------------------------------------------------------- /images/python_6.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_6.PNG -------------------------------------------------------------------------------- /images/python_alternatives.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_alternatives.png -------------------------------------------------------------------------------- /images/python_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/python_logo.png -------------------------------------------------------------------------------- /images/requeriments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/requeriments.png -------------------------------------------------------------------------------- /images/show_path_lib.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/show_path_lib.png -------------------------------------------------------------------------------- /images/tipos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/tipos.png -------------------------------------------------------------------------------- /images/types.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/types.png -------------------------------------------------------------------------------- /images/venv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/venv.png -------------------------------------------------------------------------------- /images/version_python.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/version_python.gif -------------------------------------------------------------------------------- /images/virtual_env_p3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/virtual_env_p3.png -------------------------------------------------------------------------------- /images/virtualenv.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/virtualenv.gif -------------------------------------------------------------------------------- /images/virtualenv.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/virtualenv.jpeg -------------------------------------------------------------------------------- /images/virtualenv.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/virtualenv.jpg -------------------------------------------------------------------------------- /images/virtualenv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/virtualenv.png -------------------------------------------------------------------------------- /images/which_python.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/which_python.gif -------------------------------------------------------------------------------- /images/windows_python_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/windows_python_4.png -------------------------------------------------------------------------------- /images/windows_python_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/windows_python_5.png -------------------------------------------------------------------------------- /images/windows_python_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/windows_python_6.png -------------------------------------------------------------------------------- /images/zen.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunocampos01/understanding-the-python-ecosystem/ff0a2e54bc3dc9ad5ab94a9576cc77384562ed76/images/zen.png -------------------------------------------------------------------------------- /logging_config/logging_config.ini: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [handlers] 5 | keys=stream_handler 6 | 7 | [formatters] 8 | keys=formatter 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=stream_handler 13 | 14 | [handler_stream_handler] 15 | class=StreamHandler 16 | level=DEBUG 17 | formatter=formatter 18 | args=(sys.stderr,) 19 | 20 | [formatter_formatter] 21 | format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s 22 | -------------------------------------------------------------------------------- /logging_config/test_logging.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from logging.config import fileConfig 3 | 4 | 5 | fileConfig('logging_config.ini') 6 | logger = logging.getLogger() 7 | logger.debug('often makes a very good meal of %s', 'visiting tourists') 8 | -------------------------------------------------------------------------------- /structure_python_files/1-isolated_function.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | print("This is my file to demonstrate best practices.") 4 | 5 | 6 | def process_data(data): 7 | print("Beginning data processing...") 8 | modified_data = data + " that has been modified" 9 | sleep(3) 10 | print("Data processing finished.") 11 | return modified_data 12 | -------------------------------------------------------------------------------- /structure_python_files/2-with__main__.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | print("\nThis is my file to demonstrate best practices.") 4 | 5 | 6 | def process_data(data): 7 | print("Beginning data processing...") 8 | modified_data = data + " that has been modified" 9 | sleep(3) 10 | print("Data processing finished.") 11 | return modified_data 12 | 13 | 14 | if __name__ == "__main__": 15 | # execute only if run as a script 16 | data = "My data read from the Web" 17 | print(data) 18 | modified_data = process_data(data) 19 | print(modified_data) 20 | -------------------------------------------------------------------------------- /structure_python_files/3-basic_structure.py: -------------------------------------------------------------------------------- 1 | def main(): 2 | print("My name is ROCKY BALBOA") 3 | 4 | 5 | if __name__ == "__main__": 6 | # execute only if run as a script 7 | main() 8 | -------------------------------------------------------------------------------- /structure_python_files/4-complete.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | 3 | 4 | print("This is my file to demonstrate best practices.\n") 5 | 6 | 7 | def process_data(data: str) -> str: 8 | """ 9 | Example Function with DocStrings and Annotation Function. 10 | In this file Python view the best pratices write a Python file using main() 11 | 12 | :arg: 13 | data: A data to process. 14 | :return: 15 | A data changed of type String. 16 | :raises: 17 | None 18 | """ 19 | print("Beginning data processing...") 20 | modified_data = data + " that has been modified" # type: str 21 | sleep(8) 22 | print("Data processing finished.") 23 | 24 | return modified_data 25 | 26 | 27 | def read_data_from_web(): 28 | print("Reading data from the Web") 29 | data = "Data from the web" 30 | 31 | return data 32 | 33 | 34 | def write_data_to_database(data): 35 | print("Writing data to a database") 36 | print(data) 37 | 38 | 39 | def main(): 40 | data = read_data_from_web() 41 | modified_data = process_data(data) 42 | write_data_to_database(modified_data) 43 | 44 | 45 | if __name__ == "__main__": 46 | # execute only if run as a script 47 | main() 48 | -------------------------------------------------------------------------------- /structure_python_files/5-complete_with_class.py: -------------------------------------------------------------------------------- 1 | class Animal: 2 | __hungry = "yes" 3 | __name = "no name" 4 | __owner = "no owner" 5 | 6 | def __init__(self): 7 | pass 8 | 9 | def set_owner(self, new_owner): 10 | self.__owner = new_owner 11 | return 12 | 13 | def get_owner(self): 14 | return self.__owner 15 | 16 | def set_name(self, new_name): 17 | self.__name = new_name 18 | return 19 | 20 | def get_name(self): 21 | return self.__name 22 | 23 | def noise(self): 24 | print('errr') 25 | return 26 | 27 | @staticmethod 28 | def __hidden_method(): 29 | print("hard to find") 30 | 31 | 32 | def main(): 33 | # Indentation is OUT class 34 | dog = Animal() 35 | dog.set_owner('Sue') 36 | print(dog.get_owner()) 37 | dog.noise() 38 | 39 | 40 | if __name__ == '__main__': 41 | main() 42 | -------------------------------------------------------------------------------- /structure_python_files/readme.md: -------------------------------------------------------------------------------- 1 | ## Main() 2 | 3 | Many programming languages have a special functions that is automatically executed when an operation system starts to run. 4 | 5 | This function is often called the **entry point** because it is where execution enters the program. 6 | 7 | The Python interpreter is not have special functions that serves as the entry point 8 | 9 | Nevertheless (pt:mesmo assim) have convetions to define start execution. 10 | 11 | 12 | ### A Basic Python main() 13 | ```python 14 | def main(): 15 | print("Hello World!") 16 | 17 | 18 | if __name__ == "__main__": 19 | # execute only if run as a script 20 | main() 21 | ``` 22 | 23 | ### 4 Best Practices 24 | 25 | 1. Put most code into a function or class. 26 | 2. Use `__name__` to control execution of your code. 27 | 3. Create a function called main() to contain the code you want to run. 28 | 4. Call other functions from main(). 29 | 30 | 31 | ##### Put most code into a function or class 32 | 33 | Sometimes the code you write will have side effects that you want the user to control, such as: 34 | 35 | - Running a computation that takes a long time 36 | - Writing to a file on the disk 37 | - Printing information that would clutter the user’s terminal 38 | 39 | **why?**
40 | This is because when the Python interpreter encounters the def or class keywords, it only stores those definitions for later use and doesn’t actually execute them until you tell it to. 41 | 42 | Example: `best_pratices.py` 43 | ```python 44 | from time import sleep 45 | 46 | print("This is my file to demonstrate best practices.") 47 | 48 | def process_data(data): 49 | print("Beginning data processing...") 50 | modified_data = data + " that has been modified" 51 | sleep(3) 52 | print("Data processing finished.") 53 | return modified_data 54 | 55 | ``` 56 | 57 | ##### Use __name__ to Control the Execution of Your Code 58 | 59 | ```python 60 | from time import sleep 61 | 62 | print("This is my file to demonstrate best practices.") 63 | 64 | def process_data(data): 65 | print("Beginning data processing...") 66 | modified_data = data + " that has been modified" 67 | sleep(3) 68 | print("Data processing finished.") 69 | return modified_data 70 | 71 | if __name__ == "__main__": 72 | data = "My data read from the Web" 73 | print(data) 74 | modified_data = process_data(data) 75 | print(modified_data) 76 | 77 | ``` 78 | 79 | ##### Create a Function Called main() to Contain the Code You Want to Run 80 | Although Python does not assign any significance to a function named main(), the best practice is to name the entry point function main() anyways. 81 | 82 | 83 | **why?**
84 | That way, any other programmers who read your script immediately know that this function is the starting point of the code that accomplishes the primary task of the script. 85 | ```python 86 | from time import sleep 87 | 88 | print("This is my file to demonstrate best practices.") 89 | 90 | def process_data(data): 91 | print("Beginning data processing...") 92 | modified_data = data + " that has been modified" 93 | sleep(3) 94 | print("Data processing finished.") 95 | return modified_data 96 | 97 | def main(): 98 | data = "My data read from the Web" 99 | print(data) 100 | modified_data = process_data(data) 101 | print(modified_data) 102 | 103 | if __name__ == "__main__": 104 | main() 105 | ``` 106 | 107 | ##### Call Other Functions From main() 108 | 109 | The function `main()` must execute other functions. 110 | 111 | 112 | To reuse functionality 113 | 114 | Examples: 115 | ```python 116 | from time import sleep 117 | 118 | 119 | print("This is my file to demonstrate best practices.") 120 | 121 | 122 | def process_data(data): 123 | print("Beginning data processing...") 124 | modified_data = data + " that has been modified" 125 | sleep(3) 126 | print("Data processing finished.") 127 | return modified_data 128 | 129 | 130 | def read_data_from_web(): 131 | print("Reading data from the Web") 132 | data = "Data from the web" 133 | return data 134 | 135 | 136 | def write_data_to_database(data): 137 | print("Writing data to a database") 138 | print(data) 139 | 140 | 141 | def main(): 142 | data = read_data_from_web() 143 | modified_data = process_data(data) 144 | write_data_to_database(modified_data) 145 | 146 | 147 | if __name__ == "__main__": 148 | main() 149 | ``` 150 | 151 | Now, you can run the whole processing pipeline from the command line, as shown below: 152 | 153 | ```bash 154 | $ python3 best_practices.py 155 | This is my file to demonstrate best practices. 156 | Reading data from the Web 157 | Beginning data processing... 158 | Data processing finished. 159 | Writing processed data to a database 160 | Data from the web that has been modified 161 | ``` 162 | 163 | ## References 164 | 165 | - [Some Gist][LinkGist] 166 | - [Python Docs: \_\_main\_\_][LinkPythonDocs] 167 | - [Stack Exchange: DB connections][LinkStackExchange] 168 | - [Real Python: main function][LinkRealPythonMain] 169 | - [Real Python: exceptions][LinkRealPythonExceptions] 170 | - [Real Python: handlers in logging][LinkRealPythonHandler] 171 | - [Stack Overflow: method "new"][LinkPTStackOverflowNew] 172 | - [Stack Overflow: DB how to add foreign key][LinkPTStackOverflowFK] 173 | - [Stack Overflow: create user if inexistent in MySQL][LinkStackOverflowMySQL] 174 | - [Stack Overflow: manually raising throwing exception][LinkStackOverflowException] 175 | 176 | [LinkGist]: https://gist.github.com/cabecada/da8913830960a644755b18a02b65e184 177 | [LinkPythonDocs]: https://docs.python.org/3/library/__main__.html 178 | [LinkStackExchange]: https://softwareengineering.stackexchange.com/questions/200522/how-to-deal-with-database-connections-in-a-python-library-module 179 | [LinkRealPythonMain]: https://realpython.com/python-main-function/ 180 | [LinkRealPythonExceptions]: https://realpython.com/python-exceptions/ 181 | [LinkRealPythonHandler]: https://realpython.com/python-logging/#using-handlers 182 | [LinkPTStackOverflowNew]: https://pt.stackoverflow.com/questions/109784/pra-qu%C3%AA-serve-o-metodo-new-in-python 183 | [LinkPTStackOverflowFK]: https://pt.stackoverflow.com/questions/110806/como-adicionar-uma-foreign-key-em-uma-tabela-j%C3%A1-criada 184 | [LinkStackOverflowMySQL]: https://stackoverflow.com/questions/13357760/mysql-create-user-if-not-exists 185 | [LinkStackOverflowException]: https://stackoverflow.com/questions/2052390/manually-raising-throwing-an-exception-in-python 186 | --------------------------------------------------------------------------------