├── .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 | 
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 |
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 | 
3 | 
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 |
418 |
419 |
420 |
421 |
422 |
423 |
424 |
425 |
426 |
427 | 
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 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------