├── .github └── FUNDING.yml ├── docs ├── requirements.txt ├── source │ ├── book │ │ ├── 07_files │ │ │ ├── examples.rst │ │ │ ├── further_reading.rst │ │ │ ├── open.rst │ │ │ ├── index.rst │ │ │ └── close.rst │ │ ├── Part_VII.rst │ │ ├── 24_oop_inheritance │ │ │ └── index.rst │ │ ├── 25_db │ │ │ ├── drop.rst │ │ │ ├── sql_basics.rst │ │ │ ├── further_reading.rst │ │ │ ├── sqlite3.rst │ │ │ ├── index.rst │ │ │ ├── insert.rst │ │ │ ├── sqlite3_exception.rst │ │ │ ├── select.rst │ │ │ ├── sql.rst │ │ │ ├── create.rst │ │ │ ├── sqlite3_connection_without_cursor.rst │ │ │ ├── sqlite3_cursor_as_iterator.rst │ │ │ ├── alter.rst │ │ │ └── delete.rst │ │ ├── 12_useful_modules │ │ │ └── index.rst │ │ ├── 22_oop_basics │ │ │ ├── index.rst │ │ │ ├── class_namespace.rst │ │ │ ├── create_class.rst │ │ │ ├── class_example.rst │ │ │ └── init_method.rst │ │ ├── 14_regex │ │ │ ├── index.rst │ │ │ ├── greedy_re.rst │ │ │ ├── spec_sym_sets.rst │ │ │ └── non-capturing_groups.rst │ │ ├── 03_start │ │ │ └── index.rst │ │ ├── 13_iterator_generator │ │ │ ├── index.rst │ │ │ ├── further_reading.rst │ │ │ ├── iterable.rst │ │ │ └── generator.rst │ │ ├── Part_V.rst │ │ ├── 10_useful_functions │ │ │ ├── index.rst │ │ │ ├── lambda.rst │ │ │ ├── all_any.rst │ │ │ ├── filter.rst │ │ │ └── map.rst │ │ ├── 09_functions │ │ │ ├── further_reading.rst │ │ │ ├── index.rst │ │ │ ├── namespace.rst │ │ │ └── func_params_args.rst │ │ ├── Part_I.rst │ │ ├── 01_intro │ │ │ ├── index.rst │ │ │ ├── check_python.rst │ │ │ ├── further_reading.rst │ │ │ ├── pip.rst │ │ │ └── os_and_editor.rst │ │ ├── Part_VIII.rst │ │ ├── 04_data_structures │ │ │ ├── set.rst │ │ │ ├── create_set.rst │ │ │ ├── index.rst │ │ │ ├── boolean.rst │ │ │ ├── set_operations.rst │ │ │ ├── set_methods.rst │ │ │ ├── sorting.rst │ │ │ ├── further_reading.rst │ │ │ ├── string_literal_concatenation.rst │ │ │ ├── tuple.rst │ │ │ ├── method_chaining.rst │ │ │ ├── convert_type.rst │ │ │ ├── check_type.rst │ │ │ ├── create_dict.rst │ │ │ ├── numbers.rst │ │ │ └── lists.rst │ │ ├── 08_python_basic_examples │ │ │ ├── index.rst │ │ │ └── further_reading.rst │ │ ├── 06_control_structures │ │ │ ├── index.rst │ │ │ ├── for_in_for.rst │ │ │ ├── further_reading.rst │ │ │ ├── for_if.rst │ │ │ └── for_while_else.rst │ │ ├── 02_git_github │ │ │ ├── further_reading.rst │ │ │ ├── git_basics.rst │ │ │ ├── git_basics_bash_status.rst │ │ │ ├── git_github_auth.rst │ │ │ ├── git_basics_additional.rst │ │ │ └── index.rst │ │ ├── 20_jinja2 │ │ │ ├── further_reading.rst │ │ │ ├── index.rst │ │ │ ├── README.rst │ │ │ ├── syntax_variables.rst │ │ │ ├── syntax_for.rst │ │ │ ├── assignments.rst │ │ │ └── template_syntax.rst │ │ ├── 11_modules │ │ │ ├── index.rst │ │ │ ├── module_search.rst │ │ │ └── further_reading.rst │ │ ├── 23_oop_special_methods │ │ │ ├── protocols.rst │ │ │ └── index.rst │ │ ├── additional_info │ │ │ ├── pytest.rst │ │ │ ├── old_str_formatting.rst │ │ │ ├── pyneng_on_linux.rst │ │ │ └── naming_conventions │ │ │ │ └── README.rst │ │ ├── Part_VI.rst │ │ ├── 17_serialization │ │ │ ├── further_reading.rst │ │ │ └── index.rst │ │ ├── 05_basic_scripts │ │ │ ├── executable.rst │ │ │ ├── index.rst │ │ │ ├── args.rst │ │ │ └── user_input.rst │ │ ├── 16_unicode │ │ │ ├── index.rst │ │ │ ├── further_reading.rst │ │ │ ├── unicode_standard.rst │ │ │ └── python_3_convert.rst │ │ ├── 19_concurrent_connections │ │ │ ├── index.rst │ │ │ ├── measure_script_execution_time.rst │ │ │ ├── further_reading.rst │ │ │ ├── thread_count.rst │ │ │ └── concurrent_futures.rst │ │ ├── 15_module_re │ │ │ ├── index.rst │ │ │ ├── further_reading.rst │ │ │ ├── split.rst │ │ │ ├── sub.rst │ │ │ └── match.rst │ │ ├── 21_textfsm │ │ │ ├── index.rst │ │ │ └── further_reading.rst │ │ ├── Part_IV.rst │ │ ├── Part_II.rst │ │ ├── 18_ssh_telnet │ │ │ ├── password.rst │ │ │ ├── further_reading.rst │ │ │ └── index.rst │ │ └── Part_III.rst │ ├── _templates │ │ ├── breadcrumbs.html │ │ └── footer.html │ ├── intro_index.rst │ ├── download.rst │ ├── exercises │ │ ├── 01_exercises.rst │ │ ├── pytest.rst │ │ ├── 02_exercises.rst │ │ ├── 03_exercises.rst │ │ ├── exercises_intro.rst │ │ └── 12_exercises.rst │ ├── acknowledgments.rst │ ├── index.rst │ ├── ToDo.rst │ └── about.rst ├── Makefile └── make.bat ├── .gitignore ├── .readthedocs.yaml └── README.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: natenka 2 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | furo==2022.6.21 2 | sphinx-inline-tabs 3 | sphinx_copybutton==0.5.0 4 | -------------------------------------------------------------------------------- /docs/source/book/07_files/examples.rst: -------------------------------------------------------------------------------- 1 | Примеры работы с файлами 2 | ------------------------ 3 | 4 | -------------------------------------------------------------------------------- /docs/source/_templates/breadcrumbs.html: -------------------------------------------------------------------------------- 1 | {%- extends "sphinx_rtd_theme/breadcrumbs.html" %} 2 | 3 | {% block breadcrumbs_aside %} 4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /docs/source/intro_index.rst: -------------------------------------------------------------------------------- 1 | Introduction 2 | ======== 3 | 4 | 5 | .. toctree:: 6 | :maxdepth: 1 7 | :hidden: 8 | 9 | about 10 | faq 11 | acknowledgments 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/source/book/Part_VII.rst: -------------------------------------------------------------------------------- 1 | VII. Working with databases 2 | ####################################################### 3 | 4 | .. toctree:: 5 | :maxdepth: 1 6 | :hidden: 7 | 8 | 25_db/index.rst 9 | -------------------------------------------------------------------------------- /docs/source/download.rst: -------------------------------------------------------------------------------- 1 | 2 | .. _download: 3 | 4 | Download PDF/Epub 5 | ================= 6 | 7 | * `Epub `__ 8 | * `PDF `__ 9 | -------------------------------------------------------------------------------- /docs/source/book/24_oop_inheritance/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _oop_inheritance_index: 6 | 7 | 24. Inheritance 8 | ============================ 9 | 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | :hidden: 14 | 15 | inheritance 16 | ../../exercises/24_exercises.rst 17 | -------------------------------------------------------------------------------- /docs/source/book/25_db/drop.rst: -------------------------------------------------------------------------------- 1 | DROP 2 | ~~~~ 3 | 4 | DROP operator removes table along with schema and all data. 5 | 6 | You can delete table like this: 7 | 8 | .. code:: sql 9 | 10 | new_db.db> DROP table switch; 11 | You're about to run a destructive command. 12 | Do you want to proceed? (y/n): y 13 | Your call! 14 | Query OK, 0 rows affected 15 | Time: 0.009s 16 | 17 | -------------------------------------------------------------------------------- /docs/source/book/12_useful_modules/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _useful_modules_index: 6 | 7 | 12. Useful modules 8 | ============================ 9 | 10 | This section covers these modules: 11 | 12 | 13 | .. toctree:: 14 | :maxdepth: 1 15 | :hidden: 16 | 17 | subprocess 18 | os 19 | ipaddress 20 | tabulate 21 | pprint 22 | ../../exercises/12_exercises 23 | -------------------------------------------------------------------------------- /docs/source/exercises/01_exercises.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | Exercises 6 | ~~~~~~~ 7 | 8 | Task 1.1 9 | ^^^^^^^^^^^ 10 | 11 | The only task in this section is preparation for work. 12 | 13 | To do that: 14 | 15 | * Decide which OS you want to use: 16 | * Install Python 3.7. Verify that Python and pip are installed 17 | * Create a virtual environment 18 | * Choose the editor 19 | 20 | -------------------------------------------------------------------------------- /docs/source/exercises/pytest.rst: -------------------------------------------------------------------------------- 1 | .. warning:: 2 | 3 | Starting from section "9. Functions" there are automatic tests for checking tasks. They help to check whether everything fits the task and also give feedback on what does not fit the task. As a rule, after first period of adaptation to tests, it becomes easier to do tasks with tests. 4 | 5 | :ref:`How to work with tests and basics of pytest `. 6 | 7 | -------------------------------------------------------------------------------- /docs/source/book/22_oop_basics/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _oop_basics_index: 6 | 7 | 22. OOP basics 8 | ============================ 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | :hidden: 13 | 14 | README 15 | create_class 16 | create_methods 17 | parameter_self 18 | init_method 19 | class_example 20 | class_namespace 21 | class_variables 22 | ../../exercises/22_exercises.rst 23 | -------------------------------------------------------------------------------- /docs/source/book/14_regex/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _regex_index: 6 | 7 | 14. Regular expression (regex) syntax 8 | ===================================== 9 | 10 | .. toctree:: 11 | :maxdepth: 1 12 | :hidden: 13 | 14 | syntax 15 | spec_sym_sets 16 | spec_sym_repetition 17 | spec_sym 18 | greedy_re 19 | re_groups 20 | group_example 21 | non-capturing_groups 22 | group_reference 23 | -------------------------------------------------------------------------------- /docs/source/book/03_start/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _start_index: 6 | 7 | 3. Getting started with Python 8 | ============================ 9 | 10 | 11 | This section covers: 12 | 13 | - Python syntax 14 | - Work in interactive mode 15 | - Python variables 16 | 17 | 18 | .. toctree:: 19 | :maxdepth: 1 20 | :hidden: 21 | 22 | syntax 23 | ipython 24 | ipython_magic 25 | variables 26 | ../../exercises/03_exercises 27 | -------------------------------------------------------------------------------- /docs/source/book/13_iterator_generator/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _iterator_generator_index: 6 | 7 | 13. Iterators, iterable and generators 8 | =============================================== 9 | 10 | This section discusses: 11 | 12 | - iterable 13 | - iterators 14 | - generator expressions 15 | 16 | 17 | .. toctree:: 18 | :maxdepth: 1 19 | :hidden: 20 | 21 | iterable 22 | iterator 23 | generator 24 | further_reading 25 | -------------------------------------------------------------------------------- /docs/source/book/25_db/sql_basics.rst: -------------------------------------------------------------------------------- 1 | SQL basics (in sqlite3 CLI) 2 | -------------------------- 3 | 4 | This section covers with SQL syntax. 5 | 6 | If you are familiar with basic SQL syntax you can skip this section and move 7 | to section :ref:`sqlite3_index` 8 | 9 | .. toctree:: 10 | :maxdepth: 1 11 | :hidden: 12 | 13 | create 14 | drop 15 | insert 16 | select 17 | where 18 | alter 19 | update 20 | replace 21 | delete 22 | order_by 23 | and_or_not_in 24 | -------------------------------------------------------------------------------- /docs/source/book/Part_V.rst: -------------------------------------------------------------------------------- 1 | V. Working with network devices 2 | ################################# 3 | 4 | In this part, the following topics are discussed: 5 | 6 | - SSH and Telnet connection 7 | - simultaneous connection to multiple devices 8 | - creating configuration templates with Jinja2 9 | - command output processing with TextFSM 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | :hidden: 14 | 15 | 18_ssh_telnet/index.rst 16 | 19_concurrent_connections/index.rst 17 | 20_jinja2/index.rst 18 | 21_textfsm/index.rst 19 | -------------------------------------------------------------------------------- /docs/source/book/25_db/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `SQLite Tutorial `__ - SQLite detailed description 7 | - `Module documentation 8 | sqlite3 `__ 9 | - `sqlite3 на сайте PyMOTW `__ 10 | 11 | Articles: 12 | 13 | - `A thorough guide to SQLite database operations in 14 | Python `__ 15 | 16 | -------------------------------------------------------------------------------- /docs/source/book/10_useful_functions/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _useful_functions_index: 6 | 7 | 10. Useful functions 8 | ============================ 9 | 10 | This section discusses the following functions: 11 | 12 | * print 13 | * range 14 | * sorted 15 | * enumerate 16 | * zip 17 | * all_any 18 | * lambda 19 | * map 20 | * filter 21 | 22 | 23 | .. toctree:: 24 | :maxdepth: 1 25 | :hidden: 26 | 27 | print 28 | range 29 | sorted 30 | enumerate 31 | zip 32 | all_any 33 | lambda 34 | map 35 | filter 36 | -------------------------------------------------------------------------------- /docs/source/book/09_functions/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documenation: 5 | 6 | - `Defining 7 | Functions `__ 8 | - `Built-in 9 | Functions `__ 10 | - `Sorting HOW TO `__ 11 | - `Functional Programming 12 | HOWTO `__ 13 | - `Range function `__ 14 | 15 | -------------------------------------------------------------------------------- /docs/source/book/13_iterator_generator/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation Python: 5 | 6 | - `Sequence 7 | types `__ 8 | - `Iterator 9 | types `__ 10 | - `Functional Programming 11 | HOWTO `__ 12 | 13 | Articles: 14 | 15 | - `Iterables vs. Iterators vs. 16 | Generators `__ 17 | 18 | -------------------------------------------------------------------------------- /docs/source/book/Part_I.rst: -------------------------------------------------------------------------------- 1 | I. Python basics 2 | ################ 3 | 4 | First part of the book is dedicated to Python basics. It covers: 5 | 6 | - Python data types 7 | - How to create basic scripts 8 | - Control structures 9 | - Working with files 10 | 11 | 12 | .. toctree:: 13 | :maxdepth: 1 14 | :hidden: 15 | 16 | 01_intro/index.rst 17 | 02_git_github/index.rst 18 | 03_start/index.rst 19 | 04_data_structures/index.rst 20 | 05_basic_scripts/index.rst 21 | 06_control_structures/index.rst 22 | 07_files/index.rst 23 | 08_python_basic_examples/index.rst 24 | -------------------------------------------------------------------------------- /docs/source/book/01_intro/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _intro_index: 6 | 7 | 1. Preparing for work 8 | ===================== 9 | 10 | In order to start working with Python, you need to decide on a few things: 11 | 12 | - operating system 13 | - editor 14 | - Python version 15 | 16 | This book uses Debian Linux (on other OS the output may differ slightly) and Python 3.7. 17 | 18 | 19 | .. toctree:: 20 | :maxdepth: 1 21 | :hidden: 22 | 23 | work_env 24 | os_and_editor 25 | pip 26 | virtualenv 27 | check_python 28 | further_reading 29 | ../../exercises/01_exercises.rst 30 | -------------------------------------------------------------------------------- /docs/source/exercises/02_exercises.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | Tasks 6 | ~~~~~~~ 7 | 8 | .. include:: ./exercises_intro.rst 9 | 10 | 11 | Task 2.1 12 | ^^^^^^^^^^^ 13 | 14 | Create your repository based on 15 | `repository template `__ 16 | with tasks and examples. To do this, press "Use this template". 17 | 18 | Created repository will be a copy of pyneng-examples-exercises-en repository, 19 | but is not tied to it. It's better to perform tasks in prepared files in 20 | exercises directory as tests for tasks depend on created directory structure. 21 | -------------------------------------------------------------------------------- /docs/source/book/Part_VIII.rst: -------------------------------------------------------------------------------- 1 | VIII. Additional information 2 | ############################### 3 | 4 | This section covers information that is not included in main sections of the 5 | book, but which can still be useful. 6 | 7 | .. toctree:: 8 | :maxdepth: 1 9 | :hidden: 10 | 11 | additional_info/pyneng 12 | additional_info/pytest 13 | additional_info/argparse 14 | additional_info/old_str_formatting 15 | additional_info/naming_conventions/README 16 | additional_info/naming_conventions/underscore_names 17 | additional_info/py2_vs_py3 18 | additional_info/pyneng_on_windows 19 | additional_info/pyneng_on_linux 20 | -------------------------------------------------------------------------------- /docs/source/exercises/03_exercises.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | Tasks 6 | ~~~~~~~ 7 | 8 | .. include:: ./exercises_intro.rst 9 | 10 | Task 3.1 11 | ^^^^^^^^^^^ 12 | 13 | Install IPython in a virtual environment or globally in OS. After installation, 14 | running ipython command should open IPython interpreter (the output may 15 | differ slightly): 16 | 17 | .. code:: python 18 | 19 | $ ipython 20 | Python 3.7.3 (default, May 13 2019, 15:44:23) 21 | Type 'copyright', 'credits' or 'license' for more information 22 | IPython 7.5.0 -- An enhanced Interactive Python. Type '?' for help. 23 | 24 | In [1]: 25 | 26 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SOURCEDIR = source 8 | BUILDDIR = build 9 | 10 | # Put it first so that "make" without argument is like "make help". 11 | help: 12 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 13 | 14 | .PHONY: help Makefile 15 | 16 | # Catch-all target: route all unknown targets to Sphinx using the new 17 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 18 | %: Makefile 19 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/source/exercises/exercises_intro.rst: -------------------------------------------------------------------------------- 1 | All tasks and additional files can be downloaded from 2 | `repository `__. 3 | 4 | .. warning:: 5 | 6 | Starting from section "4. Data types in Python" there are automated tests 7 | for testing tasks. They help to check whether everything matches the task, 8 | and also give feedback on what does not correspond to the task. As a rule, 9 | after the first period of adaptation to tests, it becomes easier to do tasks 10 | with tests. Testing is done using the pyneng utility. 11 | :ref:`Learn more about how to work with the pyneng utility `. 12 | -------------------------------------------------------------------------------- /docs/source/book/01_intro/check_python.rst: -------------------------------------------------------------------------------- 1 | Python interpreter 2 | ==================== 3 | 4 | Before you start, check that when you call Python interpreter, the output is: 5 | 6 | :: 7 | 8 | $ python 9 | Python 3.7.3 (default, May 13 2019, 15:44:23) 10 | [GCC 4.9.2] on linux 11 | Type "help", "copyright", "credits" or "license" for more information. 12 | 13 | Output shows that Python 3.7 is set. Invitation ``>>>``, this is a standard 14 | invitation from Python interpreter. Interpreter call is executed by python 15 | command and to exit you need to type ``quit()``, or press Ctrl+D. 16 | 17 | .. note:: 18 | Book will use ipython instead of standard Python interpreter 19 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/set.rst: -------------------------------------------------------------------------------- 1 | Set 2 | =============== 3 | 4 | Set is a mutable unordered data type. Set always contains only unique elements. 5 | Set in Python is a sequence of elements that are separated by a comma and placed 6 | in curly braces. 7 | 8 | Set can easily remove repetitive elements: 9 | 10 | .. code:: python 11 | 12 | In [1]: vlans = [10, 20, 30, 40, 100, 10] 13 | 14 | In [2]: set(vlans) 15 | Out[2]: {10, 20, 30, 40, 100} 16 | 17 | In [3]: set1 = set(vlans) 18 | 19 | In [4]: print(set1) 20 | {40, 100, 10, 20, 30} 21 | 22 | .. toctree:: 23 | :maxdepth: 1 24 | :hidden: 25 | 26 | set_methods 27 | set_operations 28 | create_set 29 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Node rules: 2 | ## Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 3 | .grunt 4 | 5 | ## Dependency directory 6 | ## Commenting this out is preferred by some people, see 7 | ## https://docs.npmjs.com/misc/faq#should-i-check-my-node_modules-folder-into-git 8 | node_modules 9 | 10 | # Book build output 11 | docs/build/ 12 | 13 | # eBook build output 14 | *.epub 15 | *.mobi 16 | pyneng.pdf 17 | 18 | # OS generated files # 19 | # ###################### 20 | .DS_Store 21 | .DS_Store? 22 | ._* 23 | .Spotlight-V100 24 | .Trashes 25 | ehthumbs.db 26 | Thumbs.db 27 | 28 | # Vim undo files. Python# 29 | # ####################### 30 | *.un~ 31 | *.pyc 32 | *.swp 33 | -------------------------------------------------------------------------------- /docs/source/book/07_files/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `Reading and Writing 7 | Files `__ 8 | - `The with 9 | statement `__ 10 | 11 | Articles: 12 | 13 | - `The Python "with" Statement by 14 | Example `__ 15 | 16 | Stack Overflow: 17 | 18 | - `What is the python “with” statement designed 19 | for? `__ 20 | 21 | -------------------------------------------------------------------------------- /docs/source/book/08_python_basic_examples/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _python_basic_examples_index: 6 | 7 | 8. Python basic examples 8 | ============================== 9 | 10 | This section covers topics that were not included in the previous sections and also provides examples of using Python to solve problems. 11 | 12 | While most examples will be file-oriented the same data-processing principles can be applied to network equipment. Only part with reading from file will be replaced to get output from hardware. 13 | 14 | .. toctree:: 15 | :maxdepth: 1 16 | :hidden: 17 | 18 | f-string 19 | variable_unpacking 20 | x_comprehensions 21 | further_reading 22 | -------------------------------------------------------------------------------- /docs/source/book/08_python_basic_examples/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `PEP 3132 -- Extended Iterable 7 | Unpacking `__ 8 | 9 | Articles: 10 | 11 | - `List, Dict And Set Comprehensions By 12 | Example `__ 13 | - `Python List Comprehensions: Explained 14 | Visually `__ 15 | 16 | Stack Overflow: 17 | 18 | - `Answer with many unpacking examples `__ 19 | 20 | -------------------------------------------------------------------------------- /docs/source/book/06_control_structures/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _control_structures_index: 6 | 7 | 6. Control structures 8 | ===================== 9 | 10 | So far, all code has been executed sequentially - all lines of script have been executed 11 | in order in which they are written in file. 12 | This section covers program flow control: 13 | 14 | * branching with ``if/elif/else`` 15 | * repeating actions using for and while loops 16 | * exception handling with ``try/except`` 17 | 18 | 19 | .. toctree:: 20 | :maxdepth: 1 21 | :hidden: 22 | 23 | if_else 24 | for 25 | while 26 | break_continue_pass 27 | for_while_else 28 | exceptions 29 | further_reading 30 | ../../exercises/06_exercises 31 | -------------------------------------------------------------------------------- /docs/source/book/02_git_github/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | Documentation: 5 | 6 | - `Informative git prompt for bash and 7 | fish `__ 8 | - `Authenticating to 9 | GitHub `__ 10 | - `Connecting to GitHub with 11 | SSH `__ 12 | 13 | About Git/GitHub: 14 | 15 | - `git/github guide. a minimal 16 | tutorial `__ - minimum knowledge required to work with Git and GitHub 17 | - `Pro Git book `__ 18 | - `Version control system (GIT) (course on 19 | Hexlet) `__ 20 | 21 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/create_set.rst: -------------------------------------------------------------------------------- 1 | Options for set creation 2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | You cannot create an empty set using a literal set (in this case it will not be a set but a dictionary): 5 | 6 | .. code:: python 7 | 8 | In [1]: set1 = {} 9 | 10 | In [2]: type(set1) 11 | Out[2]: dict 12 | 13 | But an empty set can be created in this way: 14 | 15 | .. code:: python 16 | 17 | In [3]: set2 = set() 18 | 19 | In [4]: type(set2) 20 | Out[4]: set 21 | 22 | Set from string: 23 | 24 | .. code:: python 25 | 26 | In [5]: set('long long long long string') 27 | Out[5]: {' ', 'g', 'i', 'l', 'n', 'o', 'r', 's', 't'} 28 | 29 | Set from list: 30 | 31 | .. code:: python 32 | 33 | In [6]: set([10, 20, 30, 10, 10, 30]) 34 | Out[6]: {10, 20, 30} 35 | 36 | -------------------------------------------------------------------------------- /docs/source/book/20_jinja2/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `General documentation Jinja2 `__ 7 | - `Template syntax `__ 8 | 9 | Articles: 10 | 11 | * `Network Configuration Templates Using Jinja2. Matt Oswalt `__ 12 | * `Python And Jinja2 Tutorial. Jeremy Schulman `__ 13 | * `Configuration Generator with Python and Jinja2 `__ 14 | * `Custom filters for a Jinja2 based Config Generator `__ 15 | -------------------------------------------------------------------------------- /docs/source/book/11_modules/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _modules_index: 6 | 7 | 11. Modules 8 | ============================ 9 | 10 | Module in Python is a plain text file with Python code and **.py** extention. 11 | It allows logical ordering and grouping of the code. 12 | Division into modules can be done, for example, by this logic: 13 | 14 | * division of data, formatting and code logic 15 | * grouping functions and other objects by functionality 16 | 17 | The good thing about modules is that they allow you to reuse already 18 | written code and not copy it (for example, do not copy a previously written function). 19 | 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | :hidden: 24 | 25 | import 26 | create 27 | if_name_main 28 | further_reading 29 | ../../exercises/11_exercises 30 | -------------------------------------------------------------------------------- /docs/source/book/20_jinja2/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _jinja2_index: 6 | 7 | 20. Jinja2 configuration templates 8 | ============================ 9 | 10 | Jinja2 is a template language used in Python. Jinja is not the only template 11 | language (template engine) for Python and not the only template language in general. 12 | 13 | Jinja2 is used to generate documents based on one or more templates. 14 | 15 | Examples of use: 16 | 17 | * templates for generating HTML pages 18 | * templates for generating configuration files in Unix/Linux 19 | * templates for generating network device configuration files 20 | 21 | .. toctree:: 22 | :maxdepth: 1 23 | :hidden: 24 | 25 | README 26 | example 27 | template_syntax 28 | template_inheritance 29 | further_reading 30 | ../../exercises/20_exercises 31 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # .readthedocs.yaml 2 | # Read the Docs configuration file 3 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 4 | 5 | # Required 6 | version: 2 7 | 8 | # Set the version of Python and other tools you might need 9 | build: 10 | os: ubuntu-20.04 11 | tools: 12 | python: "3.9" 13 | # You can also specify other tool versions: 14 | # nodejs: "16" 15 | # rust: "1.55" 16 | # golang: "1.17" 17 | 18 | # Build documentation in the docs/ directory with Sphinx 19 | sphinx: 20 | configuration: docs/source/conf.py 21 | 22 | # If using Sphinx, optionally build your docs in additional formats such as PDF 23 | formats: 24 | - pdf 25 | - epub 26 | 27 | # Optionally declare the Python requirements required to build your docs 28 | python: 29 | install: 30 | - requirements: docs/requirements.txt 31 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _data_structures_index: 6 | 7 | 4. Python data types 8 | ============================ 9 | 10 | Python has several data types: 11 | 12 | - Numbers 13 | - Strings 14 | - Lists 15 | - Dictionaries 16 | - Tuples 17 | - Sets 18 | - Boolean 19 | 20 | These data types, in turn, can be classified by several criteria: 21 | 22 | - mutable (lists, dictionaries and sets) 23 | - immutable (integers, strings and tuples) 24 | - ordered (lists, tuples, strings and dictionaries) 25 | - unordered (sets) 26 | 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | :hidden: 31 | 32 | README 33 | numbers 34 | strings 35 | lists 36 | dicts 37 | tuple 38 | set 39 | boolean 40 | convert_type 41 | check_type 42 | method_chaining 43 | sorting 44 | further_reading 45 | ../../exercises/04_exercises 46 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/boolean.rst: -------------------------------------------------------------------------------- 1 | Boolean values 2 | =============== 3 | 4 | Boolean values in Python are two constants ``True`` and ``False``. 5 | 6 | In Python, not only True and False are considered True and False values. 7 | 8 | * True value: 9 | 10 | * any non-zero number 11 | * any non-empty string 12 | * any non-empty object 13 | 14 | * False value: 15 | 16 | * 0 17 | * None 18 | * empty string 19 | * empty object 20 | 21 | Other True and False values tend to follow the condition logically. 22 | 23 | To check boolean value of object you can use ``bool``: 24 | 25 | .. code:: python 26 | 27 | In [2]: items = [1, 2, 3] 28 | 29 | In [3]: empty_list = [] 30 | 31 | In [4]: bool(empty_list) 32 | Out[4]: False 33 | 34 | In [5]: bool(items) 35 | Out[5]: True 36 | 37 | In [6]: bool(0) 38 | Out[6]: False 39 | 40 | In [7]: bool(1) 41 | Out[7]: True 42 | 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Python 3.7](https://img.shields.io/badge/python-3.7-blue.svg)](https://www.python.org/downloads/release/python-370/) [![Python 3.8](https://img.shields.io/badge/python-3.8-blue.svg)](https://www.python.org/downloads/release/python-380/) [![Documentation Status](https://readthedocs.org/projects/pyneng-en/badge/?version=latest)](https://pyneng.readthedocs.io/en/latest/?badge=latest) 2 | 3 | # [Python for network engineers](https://pyneng.readthedocs.io/en/latest/) 4 | 5 | * [Russian](https://pyneng.readthedocs.io/ru/latest/) 6 | * [English translation](https://pyneng.readthedocs.io/en/latest/) 7 | 8 | ## Links 9 | 10 | * ✔ [tasks](https://github.com/natenka/pyneng-examples-exercises-en/) 11 | * ✔ [answers](https://github.com/natenka/pyneng-answers-en) 12 | * 📚 [resource list](https://natenka.github.io/pyneng-resources-en/) 13 | * 💡 [code examples](https://github.com/natenka/pyneng-examples) 14 | -------------------------------------------------------------------------------- /docs/source/book/23_oop_special_methods/protocols.rst: -------------------------------------------------------------------------------- 1 | Protocols 2 | --------- 3 | 4 | Special methods are responsible not only for support of operations like 5 | addition and comparison, but also for protocol support. Protocol - set 6 | of methods that must be implemented in object to make object support a 7 | certain behavior. For example, Python has protocols like iteration, 8 | context manager, containers and others. After creating certain methods 9 | in the object, it will behave as built-in and use an interface understood 10 | by all who write on Python. 11 | 12 | .. note:: 13 | 14 | `A table with abstract classes describing which methods an object should have to make it support a certain protocol `__ 15 | 16 | 17 | .. toctree:: 18 | :maxdepth: 1 19 | :hidden: 20 | 21 | iterable_iterator 22 | sequence_protocol 23 | context_manager 24 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/set_operations.rst: -------------------------------------------------------------------------------- 1 | Operations with sets 2 | ~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | Sets are useful in performing different operations such as finding union of sets, intersection and so on. 5 | 6 | Union of sets can be obtained by ``union`` or 7 | operator ``|``: 8 | 9 | .. code:: python 10 | 11 | In [1]: vlans1 = {10,20,30,50,100} 12 | In [2]: vlans2 = {100,101,102,102,200} 13 | 14 | In [3]: vlans1.union(vlans2) 15 | Out[3]: {10, 20, 30, 50, 100, 101, 102, 200} 16 | 17 | In [4]: vlans1 | vlans2 18 | Out[4]: {10, 20, 30, 50, 100, 101, 102, 200} 19 | 20 | Intersection of sets can be obtained by 21 | ``intersection`` or operator ``&``: 22 | 23 | .. code:: python 24 | 25 | In [5]: vlans1 = {10,20,30,50,100} 26 | In [6]: vlans2 = {100,101,102,102,200} 27 | 28 | In [7]: vlans1.intersection(vlans2) 29 | Out[7]: {100} 30 | 31 | In [8]: vlans1 & vlans2 32 | Out[8]: {100} 33 | 34 | -------------------------------------------------------------------------------- /docs/source/book/additional_info/pytest.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _additional_info_pytest: 6 | 7 | Tasks checking with tests 8 | ================================= 9 | 10 | Starting with section "9. Functions" automatic tests are used to check tasks. 11 | They help to check that everything conforms to the task and also provide 12 | feedback on what is not up to task. Usually, after the first period of 13 | adaptation it becomes easier to do tasks with tests. 14 | 15 | In addition to above-mentioned positive features, tests can also show what 16 | result is expected: clarify structure of data and details that may affect the result. 17 | 18 | Pytest is used to run tests - a framework for writing tests. 19 | 20 | .. note:: 21 | 22 | `Record of lecture on using pytest for test verification `__ 23 | 24 | .. toctree:: 25 | :maxdepth: 1 26 | :hidden: 27 | 28 | pytest_basics 29 | pytest_pyneng 30 | -------------------------------------------------------------------------------- /docs/source/book/25_db/sqlite3.rst: -------------------------------------------------------------------------------- 1 | .. _sqlite3_index: 2 | 3 | Sqlite3 module 4 | -------------- 5 | 6 | Python uses sqlite3 module to work with SQLite. 7 | 8 | ``Connection`` object - this object can be said to represent a database. 9 | 10 | Example of creating a connection: 11 | 12 | .. code:: python 13 | 14 | import sqlite3 15 | 16 | connection = sqlite3.connect('dhcp_snooping.db') 17 | 18 | Once you have created a connection you should create a Cursor object which 19 | is the main way to work with database. 20 | 21 | Cursor is created from DB connection: 22 | 23 | .. code:: python 24 | 25 | connection = sqlite3.connect('dhcp_snooping.db') 26 | cursor = connection.cursor() 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | :hidden: 31 | 32 | sqlite3_execute 33 | sqlite3_fetch 34 | sqlite3_cursor_as_iterator 35 | sqlite3_connection_without_cursor 36 | sqlite3_exception 37 | sqlite3_context_manager 38 | example_sqlite 39 | -------------------------------------------------------------------------------- /docs/source/book/01_intro/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ======================== 3 | 4 | Documentation: 5 | 6 | - `Python Setup and 7 | Usage `__ 8 | - `pip `__ 9 | - `venv `__ 10 | - `virtualenvwrapper `__ 11 | 12 | Editors and IDE: 13 | 14 | - `PythonEditors `__ 15 | - `IntegratedDevelopmentEnvironments `__ 16 | - `VIM and Python - a Match Made in 17 | Heaven `__ 18 | 19 | Thonny: 20 | 21 | - `Thonny `__ 22 | - `Thonny docs `__ 23 | - `Thonny debug `__ 24 | -------------------------------------------------------------------------------- /docs/source/book/Part_VI.rst: -------------------------------------------------------------------------------- 1 | VI. Basics of object-oriented programming 2 | ####################################################### 3 | 4 | Object-oriented programming (OOP) - a programming methodology in which a program 5 | consists of objects that interact with each other. Objects are created on basis 6 | of class defined in code and typically combine data and actions that can be 7 | performed with data into a single whole. 8 | 9 | It is possible to write code without using OOP, but at a minimum learning of OOP 10 | basics will help to better understand what an object, class, method, variable are. 11 | These are things that are used in Python all the time. In addition, knowledge of 12 | OOP will be useful in reading someone else's code. For example, it will be easier 13 | to understand netmiko code. 14 | 15 | 16 | .. toctree:: 17 | :maxdepth: 1 18 | :hidden: 19 | 20 | 22_oop_basics/index.rst 21 | 23_oop_special_methods/index.rst 22 | 24_oop_inheritance/index.rst 23 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/set_methods.rst: -------------------------------------------------------------------------------- 1 | Set methods 2 | ~~~~~~~~~~~ 3 | 4 | ``add`` 5 | ^^^^^^^^^ 6 | 7 | Method ``add`` adds an item to set: 8 | 9 | .. code:: python 10 | 11 | In [1]: set1 = {10,20,30,40} 12 | 13 | In [2]: set1.add(50) 14 | 15 | In [3]: set1 16 | Out[3]: {10, 20, 30, 40, 50} 17 | 18 | ``discard`` 19 | ^^^^^^^^^^^^^ 20 | 21 | Method ``discard`` allows deleting elements without showing an error if there 22 | is no element in set: 23 | 24 | .. code:: python 25 | 26 | In [3]: set1 27 | Out[3]: {10, 20, 30, 40, 50} 28 | 29 | In [4]: set1.discard(55) 30 | 31 | In [5]: set1 32 | Out[5]: {10, 20, 30, 40, 50} 33 | 34 | In [6]: set1.discard(50) 35 | 36 | In [7]: set1 37 | Out[7]: {10, 20, 30, 40} 38 | 39 | ``clear`` 40 | ^^^^^^^^^^^ 41 | 42 | Method ``clear`` empties set: 43 | 44 | .. code:: python 45 | 46 | In [8]: set1 = {10,20,30,40} 47 | 48 | In [9]: set1.clear() 49 | 50 | In [10]: set1 51 | Out[10]: set() 52 | 53 | -------------------------------------------------------------------------------- /docs/source/book/25_db/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _db_index: 6 | 7 | 25. Database operations 8 | ============================ 9 | 10 | 11 | The use of databases is another way of storing information. Databases are useful not only in storing information. Using DBMS it is possible to make information slices according to different parameters. 12 | 13 | **Database (DB)** - data stored according to a certain scheme. This scheme describes relationships between data. 14 | **DB language (language tools)** - used to describe database structure, manage data (add, edit, delete, receive), manage access rights to database and its objects, and manage transactions. 15 | 16 | **Database Management System (DBMS)** - a software tool that enables management of DB. DBMS must support appropriate language(s) for DB management. 17 | 18 | .. toctree:: 19 | :maxdepth: 1 20 | :hidden: 21 | 22 | sql 23 | sqlite 24 | sql_basics 25 | sqlite3 26 | further_reading 27 | ../../exercises/25_exercises 28 | -------------------------------------------------------------------------------- /docs/source/book/17_serialization/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | In this section only basic read and write operations were covered with no 5 | additional parameters. More details can be found in the module documentation. 6 | 7 | * `CSV `__ 8 | * `JSON `__ 9 | * `YAML `__ 10 | 11 | In addition, `PyMOTW `__ has very good 12 | description of all Python modules that are part of the standard library 13 | (installed with Python): 14 | 15 | * `CSV `__ 16 | * `JSON `__ 17 | 18 | Example of getting JSON data via Github API: 19 | 20 | * `Example of working with Github API with requests `__ 21 | * `Writing Cyrillic and other non-ASCI characters in JSON format `__ 22 | -------------------------------------------------------------------------------- /docs/source/book/05_basic_scripts/executable.rst: -------------------------------------------------------------------------------- 1 | Executable file 2 | ~~~~~~~~~~~~~~~~ 3 | 4 | In order for a file to be executable and not have to write "python" every time before calling a file, you need to: 5 | 6 | * make file executable (for Linux) 7 | * the first line of file should have ``#!/usr/bin/env python`` 8 | or ``#!/usr/bin/env python3`` depending on which version of Python is used by default 9 | 10 | Example of access_template_exec.py file: 11 | 12 | .. code:: python 13 | 14 | #!/usr/bin/env python3 15 | 16 | access_template = ['switchport mode access', 17 | 'switchport access vlan {}', 18 | 'switchport nonegotiate', 19 | 'spanning-tree portfast', 20 | 'spanning-tree bpduguard enable'] 21 | 22 | print('\n'.join(access_template).format(5)) 23 | 24 | After that: 25 | 26 | :: 27 | 28 | chmod +x access_template_exec.py 29 | 30 | Now you can call file like this: 31 | 32 | :: 33 | 34 | $ ./access_template_exec.py 35 | 36 | -------------------------------------------------------------------------------- /docs/source/book/22_oop_basics/class_namespace.rst: -------------------------------------------------------------------------------- 1 | Class namespace 2 | ~~~~~~~~~~~~~~~ 3 | 4 | Each method in class has its own local visibility area. This means that one 5 | class method does not see variables of another class method. For variables 6 | to be available, you have to assign their instance through ``self.name``. 7 | Basically, method is a function tied to an object. Therefore, all nuances 8 | that concern function apply to methods. 9 | 10 | Variable instances are available in another method because instance itself is 11 | passed as a first argument to each method. In example below in ``__init__`` 12 | method, ``hostname`` and ``model`` variables are assigned to an instance and 13 | then used in ``info`` due to instance being passed as a first argument: 14 | 15 | .. code:: python 16 | 17 | class Switch: 18 | def __init__(self, hostname, model): 19 | self.hostname = hostname 20 | self.model = model 21 | 22 | def info(self): 23 | print(f'Hostname: {self.hostname}\nModel: {self.model}') 24 | 25 | 26 | -------------------------------------------------------------------------------- /docs/source/book/16_unicode/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _unicode_index: 6 | 7 | 16. Unicode 8 | ============================ 9 | 10 | Programs we write are not isolated. They download data from the Internet, read 11 | and write data on disk, transmit data over the network. 12 | 13 | So it's very important to understand the difference between how a computer 14 | stores and transmits data and how that data is perceived by a person. We 15 | take text, computer takes bytes. 16 | 17 | Python 3, respectively, has two concepts: 18 | 19 | * text - an immutable sequence of unicode characters. Type string (str) is used to store these characters 20 | * data - an immutable sequence of bytes. Type bytes is used for storage 21 | 22 | .. note:: 23 | 24 | It is more correct to say that text is an immutable sequence of Unicode codes (codepoints). 25 | 26 | .. toctree:: 27 | :maxdepth: 1 28 | :hidden: 29 | 30 | unicode_standard 31 | python_3_unicode 32 | python_3_convert 33 | convert_examples 34 | errors 35 | further_reading 36 | -------------------------------------------------------------------------------- /docs/source/book/19_concurrent_connections/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _concurrent_connections_index: 6 | 7 | 19. Concurent connections to multiple devices 8 | ====================================================== 9 | 10 | When you need to connect to a large number of devices, it will take quite 11 | a long time to complete the connections one by one. Of course, it will be 12 | faster than manual connection, but it would be faster to connect to equipment in parallel. 13 | 14 | Module concurrent.futures is used for parallel connection to devices 15 | in this section. 16 | 17 | .. note:: 18 | 19 | All these "long" and "faster" are relative concepts, but in this section 20 | we will learn to measure exact script execution time to compare how quick 21 | the connection is established. 22 | 23 | .. toctree:: 24 | :maxdepth: 1 25 | :hidden: 26 | 27 | measure_script_execution_time 28 | cpython_gil 29 | thread_count 30 | thread_safety 31 | logging 32 | concurrent_futures 33 | further_reading 34 | ../../exercises/19_exercises 35 | -------------------------------------------------------------------------------- /docs/source/book/25_db/insert.rst: -------------------------------------------------------------------------------- 1 | INSERT 2 | ~~~~~~ 3 | 4 | INSERT operator is used to add data to the table. 5 | 6 | .. note:: 7 | 8 | If table was deleted in previous step, create it: 9 | 10 | .. code:: sql 11 | 12 | new_db.db> create table switch (mac text not NULL primary key, hostname text, model text, location text); 13 | Query OK, 0 rows affected 14 | Time: 0.010s 15 | 16 | There are several options for adding entries, depending on whether all fields are filled and whether or not they follow the field order. 17 | 18 | If values for all fields are specified you can add an entry in this way (the order of fields must be respected): 19 | 20 | .. code:: sql 21 | 22 | new_db.db> INSERT into switch values ('0010.A1AA.C1CC', 'sw1', 'Cisco 3750', 'London, Green Str'); 23 | Query OK, 1 row affected 24 | Time: 0.008s 25 | 26 | If you want to specify not all fields or specify them randomly, this entry is used: 27 | 28 | .. code:: sql 29 | 30 | new_db.db> INSERT into switch (mac, model, location, hostname) values ('0020.A2AA.C2CC', 'Cisco 3850', 'London, Green Str', 'sw2'); 31 | Query OK, 1 row affected 32 | Time: 0.009s 33 | 34 | -------------------------------------------------------------------------------- /docs/source/book/15_module_re/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _module_re_index: 6 | 7 | 15. Module re 8 | ============================ 9 | 10 | Python uses ``re`` module to work with regular expressions. 11 | 12 | Core functions of ``re`` module: 13 | 14 | * ``match`` - searches a sequence at the beginning of the line 15 | * ``search`` - searches for first match with template 16 | * ``findall`` - searches for all matches with template. Returns the resulting strings as a list 17 | * ``finditer`` - searches for any matches with template. Returns an iterator 18 | * ``compile`` - compiles regex. You can then apply all of listed functions to this object 19 | * ``fullmatch`` - the entire line must conform to regex described 20 | 21 | In addition to functions that search matches, module has the following functions: 22 | 23 | - ``re.sub`` - for replacement in strings 24 | - ``re.split`` - to split string into parts 25 | 26 | 27 | .. toctree:: 28 | :maxdepth: 1 29 | :hidden: 30 | 31 | match_object 32 | search 33 | match 34 | finditer 35 | findall 36 | compile 37 | flags 38 | split 39 | sub 40 | further_reading 41 | ../../exercises/15_exercises 42 | -------------------------------------------------------------------------------- /docs/source/acknowledgments.rst: -------------------------------------------------------------------------------- 1 | Acknowledgments 2 | ------------- 3 | 4 | Thank you to all who expressed interest in the first announcement of the 5 | course - your interest confirmed that someone would need it. 6 | 7 | Pavel Pasynok, thank you for agreeing to course. It's been interesting 8 | working with you and it's given me an incentive to finish the course 9 | and I'm particularly glad that the knowledge that you've learned from 10 | course has found practical application. 11 | 12 | Alexey Kirillov, thank you very much :-) I have always been able to discuss 13 | with you any question on course. You helped me maintain my motivation and 14 | not get in a muddle. Communicating with you has inspired me to continue, 15 | especially in difficult moments. Thank you for your inspiration, positive 16 | emotions and support! 17 | 18 | 19 | Thanks to all those who wrote comments on book - thanks to you now book not 20 | only has fewer typographical errors and typos, but also the contents of 21 | book have improved. 22 | 23 | Thanks to all participants of online course - thanks to your questions book 24 | has become much better. 25 | 26 | Slava Skorokhod, thank you so much for volunteering to be an 27 | editor - number of errors is now going to zero :-) 28 | -------------------------------------------------------------------------------- /docs/source/book/06_control_structures/for_in_for.rst: -------------------------------------------------------------------------------- 1 | Nested for 2 | ~~~~~~~~~~~~~ 3 | 4 | Loops ``for`` can be nested in each other. 5 | 6 | In this example, *commands* is a list of commands to execute on each interface in the *fast_int* list: 7 | 8 | .. code:: python 9 | 10 | In [7]: commands = ['switchport mode access', 'spanning-tree portfast', 'spanning-tree bpduguard enable'] 11 | In [8]: fast_int = ['0/1', '0/3', '0/4', '0/7', '0/9', '0/10', '0/11'] 12 | 13 | In [9]: for intf in fast_int: 14 | ...: print('interface FastEthernet {}'.format(intf)) 15 | ...: for command in commands: 16 | ...: print(' {}'.format(command)) 17 | ...: 18 | interface FastEthernet 0/1 19 | switchport mode access 20 | spanning-tree portfast 21 | spanning-tree bpduguard enable 22 | interface FastEthernet 0/3 23 | switchport mode access 24 | spanning-tree portfast 25 | spanning-tree bpduguard enable 26 | interface FastEthernet 0/4 27 | switchport mode access 28 | spanning-tree portfast 29 | spanning-tree bpduguard enable 30 | ... 31 | 32 | The first ``for`` loop passes through interfaces in the *fast_int* list and the second through commands in *commands* list. 33 | -------------------------------------------------------------------------------- /docs/source/book/25_db/sqlite3_exception.rst: -------------------------------------------------------------------------------- 1 | Exception Handling 2 | ------------------ 3 | 4 | Let's see an example of how to use ``execute`` method when an error occurs. 5 | 6 | In switch table the mac field must be unique. If you try to write an 7 | overlapping MAC address, there is an error: 8 | 9 | .. code:: python 10 | 11 | In [37]: con = sqlite3.connect('sw_inventory2.db') 12 | 13 | In [38]: query = "INSERT into switch values ('0000.AAAA.DDDD', 'sw7', 'Cisco 2960', 'London, Green Str')" 14 | 15 | In [39]: con.execute(query) 16 | ------------------------------------------------------------ 17 | IntegrityError Traceback (most recent call last) 18 | in () 19 | ----> 1 con.execute(query) 20 | 21 | IntegrityError: UNIQUE constraint failed: switch.mac 22 | 23 | Accordingly, you can catch the exception: 24 | 25 | .. code:: python 26 | 27 | In [40]: try: 28 | ...: con.execute(query) 29 | ...: except sqlite3.IntegrityError as e: 30 | ...: print("Error occurred: ", e) 31 | ...: 32 | Error occurred: UNIQUE constraint failed: switch.mac 33 | 34 | Note that you should catch ``sqlite3.IntegrityError`` exception, 35 | not ``IntegrityError``. 36 | -------------------------------------------------------------------------------- /docs/source/book/16_unicode/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Python documentation: 5 | 6 | - 🐍 `What's New In Python 3: Text Vs. Data Instead Of Unicode Vs. 7 | 8-bit `__ 8 | - 🐍 `Unicode HOWTO `__ 9 | 10 | Articles: 11 | 12 | - 🐍 `Pragmatic Unicode `__ 13 | - article, presentation and video 14 | - 🐍 `Section «Strings» of the book "Dive Into Python 15 | 3" `__ - very well written about Unicode, encodings and how all this works in Python 16 | 17 | Without binding to Python: 18 | 19 | - `The Absolute Minimum Every Software Developer Absolutely, Positively 20 | Must Know About Unicode and Character Sets (No 21 | Excuses!) `__ 22 | - `The Unicode Consortium `__ 23 | - `Unicode (Wikipedia) `__ 24 | - `UTF-8 (Wikipedia) `__ 25 | 26 | -------------------------------------------------------------------------------- /docs/source/book/07_files/open.rst: -------------------------------------------------------------------------------- 1 | File opening 2 | --------------- 3 | 4 | To start working with a file you have to open it. 5 | 6 | ``open`` 7 | ^^^^^^^^^^ 8 | 9 | Function ``open`` is most often used to open files: 10 | 11 | .. code:: python 12 | 13 | file = open('file_name.txt', 'r') 14 | 15 | In open() function: 16 | 17 | - ``'file_name.txt'`` - file name 18 | - You can specify not only the name but also the path (absolute or relative) 19 | - ``'r'`` - file opening mode 20 | 21 | Function ``open`` creates a **file** object to which different methods can then be applied to work with it. 22 | 23 | File opening modes: 24 | 25 | * ``r`` - open file in read-only mode (default) 26 | * ``r+`` - open file for reading and writing 27 | * ``w`` - open file for writing only 28 | 29 | * if file exists, its content is removed 30 | * if file does not exist, a new one is created 31 | 32 | * ``w+`` - open file for reading and writing 33 | 34 | * if file exists, its content is removed 35 | * if file does not exist, a new one is created 36 | 37 | * ``a`` - open file to add a data. Data is added to the end of file 38 | * ``a+`` - open file for reading and writing. Data is added to the end of file 39 | 40 | .. note:: 41 | 42 | r - read; a - append; w - write 43 | -------------------------------------------------------------------------------- /docs/source/book/23_oop_special_methods/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _oop_special_methods_index: 6 | 7 | 23. Special methods 8 | ====================== 9 | 10 | Special methods in Python - methods that are responsible for "standard" 11 | possibilities of objects and are called automatically when these 12 | possibilities are used. For example, expression ``a + b`` where a and b 13 | are numbers that is converted to such a call ``a.__add__(b)``. That is, 14 | special method ``__add__`` is responsible for the addition operation. 15 | All special methods start and end with double underscore, therefore in 16 | English they are often called dunder methods, shortened from "double underscore". 17 | 18 | 19 | .. note:: 20 | 21 | Special methods are often called magic methods. 22 | 23 | Special methods are responsible for such features as working in context 24 | managers, creating iterators and iterable objects, addition operations, 25 | multiplication and others. By adding special methods to objects that 26 | are created by user, we make them look like built in Python objects. 27 | 28 | .. toctree:: 29 | :maxdepth: 1 30 | :hidden: 31 | 32 | underscore_names 33 | str_repr 34 | add_method 35 | protocols 36 | ../../exercises/23_exercises.rst 37 | -------------------------------------------------------------------------------- /docs/source/book/21_textfsm/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _textfsm_index: 6 | 7 | 21. Parsing command output with TextFSM 8 | =================================== 9 | 10 | On network devices that does not support any software interface, the output of 11 | show commands is returned as a string. And although it's partly structured, 12 | it's still just a string. And it has to be processed in some way to get 13 | Python objects, like a dictionary or a list. 14 | 15 | For example, it is possible to handle the output of a command line by line using 16 | regular expressions to get Python objects. But there is a more convenient option: TextFSM 17 | 18 | TextFSM - a library created by Google to handle output from network devices. It 19 | allows you to create templates to process the output of a command. 20 | 21 | Using TextFSM is better than simple line processing, as templates give a better 22 | idea of how output will be handled and templates are easier to share. That means 23 | it's easier to find templates that have already been created and use them or share your own. 24 | 25 | .. toctree:: 26 | :maxdepth: 1 27 | :hidden: 28 | 29 | README 30 | textfsm_syntax 31 | textfsm_examples 32 | textfsm_clitable 33 | further_reading 34 | ../../exercises/21_exercises 35 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/sorting.rst: -------------------------------------------------------------------------------- 1 | Sorting basics 2 | ============== 3 | 4 | When sorting data like list of lists or list of tuples, 5 | ``sorted`` sorts by the first element of nested lists (tuples), 6 | and if the first element is the same, on the second: 7 | 8 | .. code:: python 9 | 10 | In [1]: data = [[1, 100, 1000], [2, 2, 2], [1, 2, 3], [4, 100, 3]] 11 | 12 | In [2]: sorted(data) 13 | Out[2]: [[1, 2, 3], [1, 100, 1000], [2, 2, 2], [4, 100, 3]] 14 | 15 | 16 | If the sort is done for a list of numbers that are written as strings, 17 | the sort will be lexicographic, not natural, and the order will be: 18 | 19 | .. code:: python 20 | 21 | In [7]: vlans = ['1', '30', '11', '3', '10', '20', '30', '100'] 22 | 23 | In [8]: sorted(vlans) 24 | Out[8]: ['1', '10', '100', '11', '20', '3', '30', '30'] 25 | 26 | For the sorting to be "correct" it is necessary to convert vlans to numbers. 27 | 28 | The same problem appears, for example, with IP addresses: 29 | 30 | .. code:: python 31 | 32 | In [2]: ip_list = ["10.1.1.1", "10.1.10.1", "10.1.2.1", "10.1.11.1"] 33 | 34 | In [3]: sorted(ip_list) 35 | Out[3]: ['10.1.1.1', '10.1.10.1', '10.1.11.1', '10.1.2.1'] 36 | 37 | How to solve the problem with sorting IP addresses is discussed in section "10. Useful functions". 38 | -------------------------------------------------------------------------------- /docs/source/book/06_control_structures/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `Compound statements (if, while, for, 7 | try) `__ 8 | - `break, 9 | continue `__ 10 | - `Errors and 11 | Exceptions `__ 12 | - `Built-in 13 | Exceptions `__ 14 | 15 | Articles: 16 | 17 | - `Write Cleaner Python: Use 18 | Exceptions `__ 19 | - `Robust exception 20 | handling `__ 21 | - `Python Exception Handling 22 | Techniques `__ 23 | 24 | Stack Overflow: 25 | 26 | - `Why does python use 'else' after for and while 27 | loops? `__ 28 | - `Is it a good practice to use try-except-else in 29 | Python? `__ 30 | 31 | -------------------------------------------------------------------------------- /docs/source/book/20_jinja2/README.rst: -------------------------------------------------------------------------------- 1 | Getting started with Jinja2 2 | ====================== 3 | 4 | You can install Jinja2 using pip: 5 | 6 | .. code:: python 7 | 8 | pip install jinja2 9 | 10 | .. note:: 11 | 12 | Further, terms Jinja and Jinja2 are used interchangeably. 13 | 14 | The main idea of Jinja is to separate data and template. This allows you to use 15 | the same template but not the same data. 16 | In the simplest case, template is simply a text file that specifies locations of Jinja variables. 17 | 18 | Example of Jinja template: 19 | 20 | .. code:: jinja 21 | 22 | hostname {{name}} 23 | ! 24 | interface Loopback255 25 | description Management loopback 26 | ip address 10.255.{{id}}.1 255.255.255.255 27 | ! 28 | interface GigabitEthernet0/0 29 | description LAN to {{name}} sw1 {{int}} 30 | ip address {{ip}} 255.255.255.0 31 | ! 32 | router ospf 10 33 | router-id 10.255.{{id}}.1 34 | auto-cost reference-bandwidth 10000 35 | network 10.0.0.0 0.255.255.255 area 0 36 | 37 | Comments to template: 38 | 39 | * In Jinja, variables are written in double curly braces. 40 | * When script is executed, these variables are replaced with desired values. 41 | 42 | This template can be used to generate configuration of different devices by 43 | substituting other sets of variables. 44 | 45 | -------------------------------------------------------------------------------- /docs/source/book/25_db/select.rst: -------------------------------------------------------------------------------- 1 | SELECT 2 | ~~~~~~ 3 | 4 | SELECT operator allows you to query information from the table. 5 | 6 | For example: 7 | 8 | .. code:: sql 9 | 10 | new_db.db> SELECT * from switch; 11 | +----------------+----------+------------+-------------------+ 12 | | mac | hostname | model | location | 13 | +----------------+----------+------------+-------------------+ 14 | | 0010.A1AA.C1CC | sw1 | Cisco 3750 | London, Green Str | 15 | | 0020.A2AA.C2CC | sw2 | Cisco 3850 | London, Green Str | 16 | +----------------+----------+------------+-------------------+ 17 | 2 rows in set 18 | Time: 0.033s 19 | 20 | ``SELECT *`` means that all fields in the table must be displayed. Then indicates from which table data is requested: ``from switch``. 21 | 22 | Thus, it is possible to specify specific columns to be derived and in what order: 23 | 24 | .. code:: sql 25 | 26 | new_db.db> SELECT hostname, mac, model from switch; 27 | +----------+----------------+------------+ 28 | | hostname | mac | model | 29 | +----------+----------------+------------+ 30 | | sw1 | 0010.A1AA.C1CC | Cisco 3750 | 31 | | sw2 | 0020.A2AA.C2CC | Cisco 3850 | 32 | +----------+----------------+------------+ 33 | 2 rows in set 34 | Time: 0.033s 35 | 36 | -------------------------------------------------------------------------------- /docs/source/book/additional_info/old_str_formatting.rst: -------------------------------------------------------------------------------- 1 | String formatting with ``%`` operator 2 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | Example of ``%`` operator use: 5 | 6 | .. code:: python 7 | 8 | In [2]: "interface FastEthernet0/%s" % '1' 9 | Out[2]: 'interface FastEthernet0/1' 10 | 11 | Old string format syntax uses these symbols: 12 | 13 | * ``%s`` - string or any other object with a string type 14 | * ``%d`` - integer 15 | * ``%f`` - float 16 | 17 | Output data columns of equal width of 15 characters with right side alignment: 18 | 19 | .. code:: python 20 | 21 | In [3]: vlan, mac, intf = ['100', 'aabb.cc80.7000', 'Gi0/1'] 22 | 23 | In [4]: print("%15s %15s %15s" % (vlan, mac, intf)) 24 | 100 aabb.cc80.7000 Gi0/1 25 | 26 | Left side alignment: 27 | 28 | .. code:: python 29 | 30 | In [6]: print("%-15s %-15s %-15s" % (vlan, mac, intf)) 31 | 100 aabb.cc80.7000 Gi0/1 32 | 33 | You can also use string formatting to influence the appearance of numbers. 34 | 35 | For example, you can specify how many digits to show after comma: 36 | 37 | .. code:: python 38 | 39 | In [8]: print("%.3f" % (10.0/3)) 40 | 3.333 41 | 42 | .. note:: 43 | String formatting still has many possibilities. Good examples and 44 | explanations of two string formatting options can be found 45 | `here `__. 46 | -------------------------------------------------------------------------------- /docs/source/book/02_git_github/git_basics.rst: -------------------------------------------------------------------------------- 1 | Git fundamentals 2 | ~~~~~~~~~~ 3 | 4 | Git is a distributed version control system (Version Control System, VCS) that 5 | is widely used and released under GNU GPL v2 license. 6 | It can: 7 | 8 | - track changes in files; 9 | - store multiple versions of the same file; 10 | - cancel changes made; 11 | - record who made changes and when. 12 | 13 | Git stores changes as a snapshot of entire repository. This snapshot is created after each “commit” command. 14 | 15 | Git installation: 16 | 17 | :: 18 | 19 | $ sudo apt-get install git 20 | 21 | Git initial setup 22 | ^^^^^^^^^^^^^^^^^^^^^^^ 23 | 24 | To start working with Git you need to specify user name and e-mail that will 25 | be used to synchronize local repository with Github repository: 26 | 27 | :: 28 | 29 | $ git config --global user.name "username" 30 | $ git config --global user.email "username.user@example.com" 31 | 32 | See Git settings: 33 | 34 | :: 35 | 36 | $ git config --list 37 | 38 | Repository initialization 39 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 40 | 41 | Repository is initialized using "git init" command: 42 | 43 | :: 44 | 45 | [~/tools/first_repo] 46 | $ git init 47 | Initialized empty Git repository in /home/vagrant/tools/first_repo/.git/ 48 | 49 | After executing this command, current directory creates .git folder containing service files needed for Git. 50 | -------------------------------------------------------------------------------- /docs/source/book/19_concurrent_connections/measure_script_execution_time.rst: -------------------------------------------------------------------------------- 1 | Measure script execution time 2 | ----------------------------- 3 | 4 | There are several options for estimating execution time of the script. The 5 | simplest options are: 6 | 7 | * Linux time utility 8 | * and Python datetime module 9 | 10 | When measuring the execution time of script in this case, high accuracy is not 11 | important. The main thing is to compare the execution time of script in different variants. 12 | 13 | ``time`` 14 | ~~~~~~~~ 15 | 16 | Linux ``time`` utility allows you to measure the execution time of a script. 17 | To use ``time`` utility it is enough to write ``time`` before starting the script: 18 | 19 | :: 20 | 21 | $ time python thread_paramiko.py 22 | ... 23 | real 0m4.712s 24 | user 0m0.336s 25 | sys 0m0.064s 26 | 27 | We are interested in real time. In this case, it's 4.7 seconds. 28 | 29 | 30 | ``datetime`` 31 | ~~~~~~~~~~~~ 32 | 33 | The second option is a ``datetime`` module. This module allows working with 34 | time and dates in Python. 35 | 36 | Example: 37 | 38 | .. code:: python 39 | 40 | from datetime import datetime 41 | import time 42 | 43 | start_time = datetime.now() 44 | 45 | #Code is running here 46 | time.sleep(5) 47 | 48 | print(datetime.now() - start_time) 49 | 50 | Output: 51 | 52 | :: 53 | 54 | $ python test.py 55 | 0:00:05.004949 56 | 57 | -------------------------------------------------------------------------------- /docs/source/book/13_iterator_generator/iterable.rst: -------------------------------------------------------------------------------- 1 | .. _iterable: 2 | 3 | Iterable 4 | -------- 5 | 6 | Iteration is a generic term that describes the procedure for taking elements of 7 | something in turn. 8 | In a more general sense, it is a sequence of instructions that is repeated a 9 | certain number of times or before the specified condition is fulfilled. 10 | 11 | An iterable is an object that can return elements one at a time. It is also 12 | an object from which an iterator can be derived. 13 | 14 | Examples of iterables: 15 | 16 | * all sequences: list, string, tuple 17 | * dicts 18 | * files 19 | 20 | In Python, the ``iter`` function is responsible for getting an iterator: 21 | 22 | .. code:: python 23 | 24 | In [1]: lista = [1, 2, 3] 25 | 26 | In [2]: iter(lista) 27 | Out[2]: 28 | 29 | ``iter`` function will work on any object that has ``__iter__`` or 30 | ``__getitem__`` method. ``__iter__`` method returns an iterator. 31 | If this method is not available, ``iter`` function checks if there 32 | is ``__getitem__`` method that allows getting elements by index. 33 | 34 | If method ``__getitem__`` is present an iterator is returned, which 35 | iterates through the elements using index (starting with 0). 36 | In practice, the use of ``__getitem__`` means that all sequence elements 37 | are iterable objects. For example, a list, a tuple, a string. Although 38 | these data types have ``__iter__`` method. 39 | -------------------------------------------------------------------------------- /docs/source/book/17_serialization/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _serialization_index: 6 | 7 | 17. Working with CSV, JSON, YAML files 8 | ============================ 9 | 10 | Data serialization is about storing data in some format that is often structured. 11 | 12 | For example, it could be: 13 | 14 | * files in YAML or JSON format 15 | * files in CSV format 16 | * database 17 | 18 | In addition, Python allows you to write down objects of language itself (this 19 | aspect is not covered, but if you are interested, look at the Pickle module). 20 | 21 | This section covers CSV, JSON, YAML formats and chapter 25 covers databases. 22 | 23 | YAML, JSON, CSV formats usage: 24 | 25 | * you may have data about IP address and similar information to process in tables 26 | 27 | * table can be exported to CSV format and processed by Python 28 | 29 | * software can return data in JSON format. Accordingly, by converting this data into a Python object you can work with it and do whatever you want 30 | * YAML is very convenient to use to describe parameters 31 | 32 | * for example, it can be settings for different objects (IP addresses, VLANs, etc.) 33 | * at least knowing YAML format will be useful when using Ansible 34 | 35 | For each of these formats, Python has a module that makes them easier to work with. 36 | 37 | .. toctree:: 38 | :maxdepth: 1 39 | :hidden: 40 | 41 | csv 42 | json 43 | yaml 44 | further_reading 45 | ../../exercises/17_exercises 46 | -------------------------------------------------------------------------------- /docs/source/book/Part_IV.rst: -------------------------------------------------------------------------------- 1 | IV. Data writing and transmission 2 | ############################ 3 | 4 | This part of the book covers data writing and transmission. Data can be, for example: 5 | 6 | - command output 7 | - processed output of commands as dictionary, list or similar 8 | - information from monitoring system 9 | 10 | So far, only the simplest option has been covered - writing information 11 | to a plain text file. 12 | 13 | This section covers data reading and writing in CSV, JSON and YAML formats: 14 | 15 | - CSV - a tabular format of data presentation. It can be obtained, for example, 16 | by exporting data from a table or database. Similarly, data can be written in 17 | this format for further import into the table. 18 | - JSON - a format that is often used in API. In addition, this format will 19 | allow you to save data structures such as dictionaries or lists in a 20 | structured format and then read them from a JSON file and get the same 21 | data structures in Python. 22 | - YAML format is often used to describe playbooks. For example, it is used 23 | in Ansible. In addition, in this format it is convenient to write manually 24 | the parameters that should be read by scripts. 25 | 26 | .. note:: 27 | 28 | Python allows objects of language itself to be written into files and read 29 | through Pickle module, but this topic is not covered in this book. 30 | 31 | 32 | .. toctree:: 33 | :maxdepth: 1 34 | :hidden: 35 | 36 | 16_unicode/index.rst 37 | 17_serialization/index.rst 38 | -------------------------------------------------------------------------------- /docs/source/book/21_textfsm/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `TextFSM `__ 7 | 8 | Articles: 9 | 10 | * `Programmatic Access to CLI Devices with TextFSM. Jason Edelman (26.02.2015) `__ - 11 | TextFSM basics and development ideas that formed the basis of ntc-ansible module 12 | * `Parse CLI outputs with TextFSM. Henry Ölsner (24.08.2015) `__ 13 | - an example of using TextFSM to parse a large file with *sh inventory* output. Explains TextFSM syntax in more detail 14 | * `Creating Templates for TextFSM and ntc_show_command. Jason Edelman (27.08.2015) `__ 15 | - TextFSM syntax is discussed in more detail and examples of ntc-ansible module usage are shown 16 | (note that syntax of module has already changed slightly) 17 | * `TextFSM and Structured Data. Kirk Byers (22.10.2015) `__ - an introductory article on TextFSM. This does not describe syntax but gives an overview of what TextFSM is and an example of its use 18 | 19 | Projects that use TextFSM: 20 | 21 | * `Module ntc-ansible `__ 22 | 23 | TextFSM templates (from ntc-ansible module): 24 | 25 | * `ntc-templates `__ 26 | -------------------------------------------------------------------------------- /docs/source/book/25_db/sql.rst: -------------------------------------------------------------------------------- 1 | SQL 2 | --- 3 | 4 | **SQL (structured query language)** - used to describe database structure, 5 | manage data (add, edit, delete, receive), manage access rights to database 6 | and its objects, and manage transactions. 7 | 8 | SQL language is divided into the following categories: 9 | 10 | * DDL (Data Definition Language) 11 | * DML (Data Manipulation Language) 12 | * DCL (Data Control Language) 13 | * TCL (Transaction Control Language) 14 | 15 | Each category has its own operators (not all operators are listed): 16 | 17 | * DDL 18 | 19 | * CREATE - create new table, DBMS, schemas 20 | * ALTER - change of existing table, columns 21 | * DROP - removing existing objects from DBMS 22 | 23 | * DML 24 | 25 | * SELECT - data selection 26 | * INSERT - adding new data 27 | * UPDATE - updating existing data 28 | * DELETE - deleting data 29 | 30 | * DCL 31 | 32 | * GRANT - Allow users to read/write certain objects to DBMS 33 | * REVOKE - - withdrawal of prior authorizations 34 | 35 | * TCL 36 | 37 | * COMMIT - committing of transaction 38 | * ROLLBACK - rollback of all changes made in the current transaction 39 | 40 | SQL and Python 41 | ^^^^^^^^^^^^ 42 | 43 | Two approaches can be used to work with a relational DBMS in Python: 44 | 45 | * work with a library that corresponds to a specific database and use SQL language to work with database. For example, sqlite uses sqlite3 module 46 | * work with `ORM `__ which uses an object-oriented approach to work with database. For example, Sqlalchemy 47 | -------------------------------------------------------------------------------- /docs/source/book/16_unicode/unicode_standard.rst: -------------------------------------------------------------------------------- 1 | Unicode standard 2 | --------------- 3 | 4 | Unicode is a standard that describes the representation and encoding of almost 5 | all languages and other characters. 6 | 7 | A few facts about Unicode: 8 | 9 | * version 13.0 (March 2020) describes 143 859 codes 10 | * each code is a number that corresponds to a certain character 11 | * standard also defines the encoding - the way of representing the symbol code in bytes 12 | 13 | Each character in Unicode has a specific code. This is a number that is usually 14 | written as follows: ``U+0073``, where 0073 - hexadecimal digits. 15 | Apart from the code, each symbol has its own unique name. For example, 16 | letter "s" corresponds to code ``U+0073`` and the name "LATIN SMALL LETTER S". 17 | 18 | Examples of codes, names and corresponding symbols: 19 | 20 | - ``U+0073``, "LATIN SMALL LETTER S" - s 21 | - ``U+00F6``, "LATIN SMALL LETTER O WITH DIAERESIS" - ö 22 | - ``U+1F383``, "JACK-O-LANTERN" - 🎃 23 | - ``U+2615``, "HOT BEVERAGE" - ☕ 24 | - ``U+1f600``, "GRINNING FACE" - 😀 25 | 26 | Encodings 27 | ~~~~~~~~~ 28 | 29 | Encodings allow to write character code in bytes. 30 | 31 | Unicode supports several encodings: 32 | 33 | * UTF-8 34 | * UTF-16 35 | * UTF-32 36 | 37 | One of the most popular encoding to date is UTF-8. This encoding uses a variable 38 | number of bytes to write Unicode characters. 39 | 40 | Examples of Unicode characters and their representation in bytes in UTF-8 encoding: 41 | 42 | * H - ``48`` 43 | * i - ``69`` 44 | * 🛀 - ``01 f6 c0`` 45 | * 🚀 - ``01 f6 80`` 46 | * ☃ - ``26 03`` 47 | 48 | -------------------------------------------------------------------------------- /docs/source/book/14_regex/greedy_re.rst: -------------------------------------------------------------------------------- 1 | Greedy qualifiers 2 | ----------------- 3 | 4 | By default, ``*``, ``+``, and ``?`` qualifiers are all greedy - they match 5 | as much text as possible. 6 | 7 | An example of greedy behavior: 8 | 9 | .. code:: python 10 | 11 | In [1]: import re 12 | 13 | In [2]: line = ' some text>' 14 | 15 | In [3]: match = re.search('<.*>', line) 16 | 17 | In [4]: match.group() 18 | Out[4]: ' some text>' 19 | 20 | In this case, expression captured maximum possible piece of symbols contained 21 | in ``<>``. If greedy behavior need to be disabled, just add a question mark 22 | after the repetition symbols: 23 | 24 | .. code:: python 25 | 26 | In [5]: line = ' some text>' 27 | 28 | In [6]: match = re.search('<.*?>', line) 29 | 30 | In [7]: match.group() 31 | Out[7]: '' 32 | 33 | But greed is often useful. For example, without turning off greed of the last 34 | plus, expression ``\d+\s+\S+`` describes line: 35 | 36 | .. code:: python 37 | 38 | In [8]: line = '1500 aab1.a1a1.a5d3 FastEthernet0/1' 39 | 40 | In [9]: re.search('\d+\s+\S+', line).group() 41 | Out[9]: '1500 aab1.a1a1.a5d3' 42 | 43 | Symbol ``\S`` denotes everything except whitespace characters. Therefore, 44 | expression ``\S+`` with greedy repetition symbol describes maximum long 45 | string until the first whitespace character. In this case up to the first space. 46 | 47 | If greed is disabled, the result is: 48 | 49 | .. code:: python 50 | 51 | In [10]: re.search('\d+\s+\S+?', line).group() 52 | Out[10]: '1500 a' 53 | 54 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `Strings `__. 7 | `String 8 | Methods `__ 9 | - `Lists 10 | basics `__. 11 | `More on 12 | lists `__ 13 | - `Tuples `__. 14 | `More on 15 | tuples `__ 16 | - `Sets 17 | basics `__. 18 | `More on 19 | sets `__ 20 | - `Dict 21 | basics `__. 22 | `More on 23 | dicts `__ 24 | - `Common Sequence 25 | Operations `__ 26 | 27 | String formatting: 28 | 29 | - `String formating usage examples `__ 30 | - `Documentaion on string formating `__ 31 | - `Python 3's f-Strings: An Improved String Formatting Syntax 32 | (Guide) `__ 33 | - `Python String Formatting Best 34 | Practices `__ 35 | 36 | -------------------------------------------------------------------------------- /docs/source/book/05_basic_scripts/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _basic_scripts_index: 6 | 7 | 5. Basic scripts 8 | ================ 9 | 10 | Generally speaking, script is a regular file. This file stores the sequence of commands that you want to execute. 11 | 12 | Let's start with basic script and print several strings on standard output. 13 | To do this, you need to create an access_template.py file with this content: 14 | 15 | .. code:: python 16 | 17 | access_template = ['switchport mode access', 18 | 'switchport access vlan {}', 19 | 'switchport nonegotiate', 20 | 'spanning-tree portfast', 21 | 'spanning-tree bpduguard enable'] 22 | 23 | print('\n'.join(access_template).format(5)) 24 | 25 | First, items in list are combined into a string that is separated by ``\n`` 26 | and VLAN number is inserted into string using string formatting. 27 | After this you should save file and go to command line. 28 | This is how the script execution looks like: 29 | 30 | .. code:: python 31 | 32 | $ python access_template.py 33 | switchport mode access 34 | switchport access vlan 5 35 | switchport nonegotiate 36 | spanning-tree portfast 37 | spanning-tree bpduguard enable 38 | 39 | 40 | All scripts that will be created in this course have an extension ``.py``. You can say that it is a «good manners» - to create Python scripts with .py extension. 41 | 42 | .. toctree:: 43 | :maxdepth: 1 44 | :hidden: 45 | 46 | executable 47 | args 48 | user_input 49 | ../../exercises/05_exercises 50 | -------------------------------------------------------------------------------- /docs/source/book/10_useful_functions/lambda.rst: -------------------------------------------------------------------------------- 1 | Anonymous function (lambda expression) 2 | ------------------------------------ 3 | 4 | In Python, ``lambda`` expression allows creation of anonymous functions - functions that are not tied to a name. 5 | 6 | Anonymous function: 7 | 8 | * may contain only one expression 9 | * can pass as many arguments as you want 10 | 11 | Standard function: 12 | 13 | .. code:: python 14 | 15 | In [1]: def sum_arg(a, b): return a + b 16 | 17 | In [2]: sum_arg(1, 2) 18 | Out[2]: 3 19 | 20 | Similar anonymous function or ``lambda`` function: 21 | 22 | .. code:: python 23 | 24 | In [3]: sum_arg = lambda a, b: a + b 25 | 26 | In [4]: sum_arg(1, 2) 27 | Out[4]: 3 28 | 29 | Note that there is no **return** operator in ``lambda`` function definition 30 | because there can only be one expression in this function that always returns 31 | a value and closes the function. 32 | 33 | Function ``lambda`` is convenient to use in expressions where you need 34 | to write a small function for data processing. 35 | For example, in ``sorted`` function you can use lambda expression to specify sorting key: 36 | 37 | .. code:: python 38 | 39 | In [5]: list_of_tuples = [('IT_VLAN', 320), 40 | ...: ('Mngmt_VLAN', 99), 41 | ...: ('User_VLAN', 1010), 42 | ...: ('DB_VLAN', 11)] 43 | 44 | In [6]: sorted(list_of_tuples, key=lambda x: x[1]) 45 | Out[6]: [('DB_VLAN', 11), ('Mngmt_VLAN', 99), ('IT_VLAN', 320), ('User_VLAN', 1010)] 46 | 47 | Function ``lambda`` is also useful in ``map`` and ``filter`` functions which will be discussed in the following sections. 48 | -------------------------------------------------------------------------------- /docs/source/book/02_git_github/git_basics_bash_status.rst: -------------------------------------------------------------------------------- 1 | Displaying repository status in invitation 2 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 3 | 4 | This is an additional functionality that is not required to work with Git but 5 | is very helpful in this regard. When working with Git it is very convenient when 6 | you can immediately determine whether you are in a regular directory or in a 7 | Git repository. In addition, it would be good to understand status of current 8 | repository. To do this, you need to install a special 9 | `utility `__ that will show 10 | status of repository. To install utility, copy its repository to user's home 11 | directory under which you work: 12 | 13 | .. code:: shell 14 | 15 | cd ~ 16 | git clone https://github.com/magicmonty/bash-git-prompt.git .bash-git-prompt --depth=1 17 | 18 | And then add to the end of ``~/.bashrc`` file such lines: 19 | 20 | .. code:: shell 21 | 22 | GIT_PROMPT_ONLY_IN_REPO=1 23 | source ~/.bash-git-prompt/gitprompt.sh 24 | 25 | To apply changes, restart bash: 26 | 27 | .. code:: shell 28 | 29 | exec bash 30 | 31 | In my configuration command line invitation is spread over several lines, so 32 | you will have a different one. Please note that additional information 33 | appears when you move to repository. 34 | 35 | Now, if you're in a regular catalog, invitation is like this: 36 | 37 | :: 38 | 39 | [~] 40 | vagrant@jessie-i386: 41 | $ 42 | 43 | If you go to Git repository: 44 | 45 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/setup_prompt.png 46 | 47 | 48 | -------------------------------------------------------------------------------- /docs/source/book/15_module_re/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Regular expressions in Python: 5 | 6 | - `Regular Expression 7 | HOWTO `__ 8 | - `Python 3 Module of the Week. Module re `__ 9 | 10 | Websites for regular expressions checking: 11 | 12 | * `regex101 `__ 13 | * `for Python `__ - you can specify search, match, findall methods and flags. 14 | `An example of a regular expression `__. 15 | Unfortunately, sometimes not all expressions are perceived. 16 | * `Another site for Python `__ - does not support methods but works well and has worked out the expressions which didn't work in previous site. It's perfect for one-line text. With the multiline, it worth considering that Python will have a different situation. 17 | 18 | General guidance on the use of regular expressions: 19 | 20 | - `Many examples of the use of regular expressions from basics to more complex themes `__ 21 | - `Book Mastering Regular 22 | Expressions `__ 23 | 24 | Assistance in the study of regular expressions: 25 | 26 | - `Visualize regular expression `__ 27 | - `Regex Cross­word `__ 28 | 29 | -------------------------------------------------------------------------------- /docs/source/book/11_modules/module_search.rst: -------------------------------------------------------------------------------- 1 | Пути поиска модулей 2 | ------------------- 3 | 4 | При импорте модуля, Python ищет модуль в таком порядке: \* в текущем 5 | каталоге \* если модуль не найден, Python ищет модуль в каталогах, 6 | которые указаны в переменной PYTHONPATH \* если модуль не найден, Python 7 | проверяет путь по умолчанию. В Unix это, как правило, 8 | /usr/local/lib/python/ 9 | 10 | Пути поиска модулей хранятся в переменной sys.path: 11 | 12 | .. code:: python 13 | 14 | In [1]: import sys 15 | 16 | In [2]: sys.path 17 | Out[2]: 18 | ['', 19 | '/usr/local/bin', 20 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip', 21 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7', 22 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin', 23 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac', 24 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages', 25 | '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python', 26 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk', 27 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old', 28 | '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload', 29 | '/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/PyObjC', 30 | '/Library/Python/2.7/site-packages', 31 | '/Library/Python/2.7/site-packages/IPython/extensions', 32 | '/Users/natasha/.ipython'] 33 | 34 | -------------------------------------------------------------------------------- /docs/source/book/22_oop_basics/create_class.rst: -------------------------------------------------------------------------------- 1 | Class creation 2 | --------------- 3 | 4 | .. note:: 5 | 6 | Note that the basis is explained here given that the reader has no experience 7 | with OOP. Some examples are not very correct from Python's ideology point of view, 8 | but they help to better understand how it works. At the end, an explanation is 9 | given of how this should be done in proper way. 10 | 11 | Keyword ``class`` is used in python to create classes. The easiest class you can create in Python: 12 | 13 | .. code:: python 14 | 15 | In [1]: class Switch: 16 | ...: pass 17 | ...: 18 | 19 | .. note:: 20 | 21 | Class names: usually class names in Python are written in CamelCase format. 22 | 23 | To create a class instance, call class: 24 | 25 | .. code:: python 26 | 27 | In [2]: sw1 = Switch() 28 | 29 | In [3]: print(sw1) 30 | <__main__.Switch object at 0xb44963ac> 31 | 32 | Using dot notation, it is possible to get values of instance variables, create 33 | new variables and assign a new value to existing ones: 34 | 35 | .. code:: python 36 | 37 | In [5]: sw1.hostname = 'sw1' 38 | 39 | In [6]: sw1.model = 'Cisco 3850' 40 | 41 | In another instance of Switch class, the variables may be different: 42 | 43 | .. code:: python 44 | 45 | In [7]: sw2 = Switch() 46 | 47 | In [8]: sw2.hostname = 'sw2' 48 | 49 | In [9]: sw2.model = 'Cisco 3750' 50 | 51 | You can see value of instance variables using the same dot notation: 52 | 53 | .. code:: python 54 | 55 | In [10]: sw1.model 56 | Out[10]: 'Cisco 3850' 57 | 58 | In [11]: sw2.model 59 | Out[11]: 'Cisco 3750' 60 | 61 | -------------------------------------------------------------------------------- /docs/source/book/Part_II.rst: -------------------------------------------------------------------------------- 1 | II. Code reuse 2 | ################################ 3 | 4 | When writing code, some of the steps are often repeated. It can be a small 5 | block of 3-5 lines, or it can be a fairly large sequence of steps. 6 | Copying code is a bad idea. Because if you have to update one of copies later, 7 | you have to update others. 8 | 9 | Instead, you create a special code block with name - function. And every 10 | time code has to be repeated, you just call a function. Function allows 11 | not only to name a block of code but also to make it more abstract through 12 | parameters. Parameters make it possible to pass different data 13 | for function. And get different results depending on input parameters. 14 | 15 | Section :ref:`functions_index` covers with creation of functions, 16 | section :ref:`useful_functions_index` discusses useful built-in functions. 17 | 18 | Once code is divided into functions, there comes a time when you 19 | need to use function in another script. Of course, copying a 20 | function is as inconvenient as copying a normal code. Modules are used 21 | to reuse code from another Python script. 22 | 23 | Section :ref:`modules_index` is dedicated to creating your own modules 24 | and section :ref:`useful_modules_index` covers useful modules 25 | from Python standard library. 26 | 27 | The last section :ref:`iterator_generator_index` is dedicated to iterable 28 | objects, iterators and generators. 29 | 30 | .. toctree:: 31 | :maxdepth: 1 32 | :hidden: 33 | 34 | 09_functions/index.rst 35 | 10_useful_functions/index.rst 36 | 11_modules/index.rst 37 | 12_useful_modules/index.rst 38 | 13_iterator_generator/index.rst 39 | -------------------------------------------------------------------------------- /docs/source/book/07_files/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _files_index: 6 | 7 | 7. Working with files 8 | ============================ 9 | 10 | In real life, in order to make full use of everything covered before this section you need to understand how to work with files. 11 | 12 | When working with network equipment (and not only), files can be: 13 | 14 | * configurations (simple, non-structured text files) 15 | 16 | * They are discussed in this section 17 | 18 | * configuration templates 19 | 20 | * usually a special file format. 21 | * section `Jinja configuration temlates <../21_jinja2/>`__ discusses the use of Jinja2 to create configuration templates 22 | 23 | * files with connection options 24 | 25 | * usually they are structured files in some particular format: YAML, JSON, CSV 26 | 27 | * section `Data serialization <../17_serialization/>`__ discusses how to handle such files 28 | 29 | * other Python scripts 30 | 31 | * section `Modules <../11_modules/>`__ discusses how to work with modules (other Python scripts) 32 | 33 | This section covers simple text files. For example, Cisco configuration file. 34 | 35 | There are several aspects to working with files: 36 | 37 | * opening/closing 38 | * reading 39 | * writing 40 | 41 | This section covers only the minimum required for working with files. More in 42 | `Python documentation `__. 43 | 44 | .. toctree:: 45 | :maxdepth: 1 46 | :hidden: 47 | 48 | open 49 | read 50 | write 51 | close 52 | with 53 | working_with_files 54 | further_reading 55 | ../../exercises/07_exercises 56 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/string_literal_concatenation.rst: -------------------------------------------------------------------------------- 1 | Literal strings concatenation 2 | --------------------------- 3 | 4 | Python has very convenient functionality — literal strings concatenation 5 | 6 | .. code:: python 7 | 8 | In [1]: s = ('Test' 'String') 9 | 10 | In [2]: s 11 | Out[2]: 'TestString' 12 | 13 | In [3]: s = 'Test' 'String' 14 | 15 | In [4]: s 16 | Out[4]: 'TestString' 17 | 18 | You can even wrap parts of a line on different lines, but only if they are 19 | in parentheses: 20 | 21 | .. code:: python 22 | 23 | In [5]: s = ('Test' 24 | ...: 'String') 25 | 26 | In [6]: s 27 | Out[6]: 'TestString' 28 | 29 | This is very convenient to use in regex: 30 | 31 | .. code:: python 32 | 33 | regex = ( 34 | '(\S+) +(\S+) +' 35 | '\w+ +\w+ +' 36 | '(up|down|administratively down) +' 37 | '(\w+)' 38 | ) 39 | 40 | This way, the regex can be split and made easier to understand. Plus you can 41 | add explanatory comments in strings. 42 | 43 | .. code:: python 44 | 45 | regex = ( 46 | '(\S+) +(\S+) +' # interface and IP 47 | '\w+ +\w+ +' 48 | '(up|down|administratively down) +' # Status 49 | '(\w+)' # Protocol 50 | ) 51 | 52 | It is also convenient to use this technique when writing a long message: 53 | 54 | .. code:: python 55 | 56 | In [7]: message = ('During command execution "{}" ' 57 | ...: 'such error occured "{}".\n' 58 | ...: 'Exclude this command from the list? [y/n]') 59 | 60 | In [8]: message 61 | Out[8]: 'During command execution "{}" such error occured "{}".\nExclude this command from the list? [y/n]' 62 | 63 | -------------------------------------------------------------------------------- /docs/source/book/18_ssh_telnet/password.rst: -------------------------------------------------------------------------------- 1 | Password input 2 | ----------- 3 | 4 | During manual connection to device the password is also manually entered. 5 | 6 | When automating connection it is necessary to decide how password will be transmitted: 7 | 8 | * Request password at start of the script and read user input. Disadvantage is that you can see which characters user is typing 9 | * Write login and password in some file (it's not secure). 10 | 11 | As a rule, the same user uses the same login and password to connect to devices. 12 | And usually it's enough to request login and password at the start of the 13 | script and then use them to connect to different devices. 14 | 15 | Unfortunately, if you use ``input`` the typed password will be visible. 16 | But it is better if no characters are displayed when entering a password. 17 | 18 | Module getpass 19 | ~~~~~~~~~~~~~~ 20 | 21 | Module getpass allows you to request a password without displaying input characters: 22 | 23 | .. code:: python 24 | 25 | In [1]: import getpass 26 | 27 | In [2]: password = getpass.getpass() 28 | Password: 29 | 30 | In [3]: print(password) 31 | testpass 32 | 33 | Environment variables 34 | ~~~~~~~~~~~~~~~~~~~~ 35 | 36 | Another way to store a password (or even a username) is by environment variables. 37 | 38 | For example, login and password are written in variables: 39 | 40 | :: 41 | 42 | $ export SSH_USER=user 43 | $ export SSH_PASSWORD=userpass 44 | 45 | And then Python reads values to variables in the script: 46 | 47 | .. code:: python 48 | 49 | import os 50 | 51 | USERNAME = os.environ.get('SSH_USER') 52 | PASSWORD = os.environ.get('SSH_PASSWORD') 53 | 54 | -------------------------------------------------------------------------------- /docs/source/book/18_ssh_telnet/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Documentation: 5 | 6 | - `pexpect `__ 7 | - `telnetlib `__ 8 | - `paramiko Client `__ 9 | - `paramiko 10 | Channel `__ 11 | - `netmiko `__ 12 | - `scrapli `__ 13 | - `scrapli-cfg `__ 14 | - `time `__ 15 | - `datetime `__ 16 | - `getpass `__ 17 | 18 | Articles: 19 | 20 | * `Netmiko Library `__ 21 | * `Automate SSH connections with netmiko `__ 22 | * `Network Automation Using Python: BGP Configuration `__ 23 | * `A Tale of Five Python SSH Libraries Commentary `__ 24 | 25 | Code examples: 26 | 27 | * `netmiko `__ 28 | * `scrapli `__ 29 | * `netmiko, paramiko, telnetlib, scrapli, pexpect `__ 30 | -------------------------------------------------------------------------------- /docs/source/book/11_modules/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | The Python Standard Library: 5 | 6 | - `Python Module Index `__ 7 | - `Python 3 Module of the Week `__ 8 | 9 | Docs: 10 | 11 | - `Python tutorial. 12 | Modules `__ 13 | - `os `__ 14 | - `argparse `__ 15 | - `subprocess `__ 16 | - `ipaddress `__ 17 | 18 | Video: 19 | 20 | - `David Beazley - Modules and Packages: Live and Let Die! - PyCon 21 | 2015 `__ 22 | 23 | argparse 24 | ~~~~~~~~ 25 | 26 | - `Argparse docs `__ 27 | - `PyMOTW `__ 28 | 29 | tabulate 30 | ~~~~~~~~ 31 | 32 | - `tabulate docs `__ 33 | - `Pretty printing tables in Python `__ 34 | - `Tabulate 0.7.1 with LaTeX & MediaWiki tables `__ 35 | 36 | Stack Overflow: 37 | 38 | - `Printing Lists as Tabular Data `__. 39 | 40 | pprint 41 | ~~~~~~ 42 | 43 | - `pprint — Data pretty 44 | printer `__ 45 | - `PyMOTW. pprint — Pretty-Print Data 46 | Structures `__ 47 | 48 | -------------------------------------------------------------------------------- /docs/source/book/Part_III.rst: -------------------------------------------------------------------------------- 1 | III. Regular expressions 2 | ######################### 3 | 4 | A regular expression is a sequence of ordinary and special characters. 5 | This sequence specifies a template that is later used to find search pattern. 6 | 7 | When working with network equipment, regular expressions can be used, for example, to: 8 | 9 | * retrieve information from show command output 10 | * select a portion of lines from show command output that matches the template 11 | * check whether there are certain settings in configuration 12 | 13 | A few examples are: 14 | 15 | * After processing the output of show version command, you can collect 16 | information about OS version and uptime. 17 | * get from log file the lines that correspond to the template. 18 | * get from configuration those interfaces that do not have a description 19 | 20 | In addition, in network equipment the regular expressions can be used to filter 21 | the output of any show commands. 22 | 23 | In general, use of regular expressions will involve getting part of a text 24 | out of a large output. But that's not the only thing they can be used for. 25 | For example, regular expressions can be used to perform string replacements 26 | or for dividing a string. 27 | 28 | These areas of use overlap with methods that apply to strings. And if problemi 29 | is clear and simple to solve with string methods, it is better to use them. 30 | This code will be easier to understand and, in addition, string methods work faster. 31 | 32 | But string methods may not solve all problems or may make problem much harder 33 | to solve. Regular expressions can help in this case. 34 | 35 | .. toctree:: 36 | :maxdepth: 1 37 | :hidden: 38 | 39 | 14_regex/index.rst 40 | 15_module_re/index.rst 41 | -------------------------------------------------------------------------------- /docs/source/book/25_db/create.rst: -------------------------------------------------------------------------------- 1 | CREATE 2 | ~~~~~~ 3 | 4 | CREATE TABLE statement allows you to create tables. 5 | 6 | First connect to database or create it with litecli: 7 | 8 | :: 9 | 10 | $ litecli new_db.db 11 | Version: 1.0.0 12 | Mail: https://groups.google.com/forum/#!forum/litecli-users 13 | Github: https://github.com/dbcli/litecli 14 | new_db.db> 15 | 16 | 17 | Create a *switch* table which stores information about switches: 18 | 19 | .. code:: sql 20 | 21 | new_db.db> create table switch (mac text not NULL primary key, hostname text, model text, location text); 22 | Query OK, 0 rows affected 23 | Time: 0.010s 24 | 25 | 26 | In this example, we described *switch* table: we defined which fields would be in the table and which types of values would be in them. 27 | 28 | Additionally, *mac* field is primary key. That automatically means that: 29 | 30 | * field must be unique 31 | * field cannot have null value (in SQLite this must be stated explicitly) 32 | 33 | In this example this is quite logical as MAC address must be unique. 34 | 35 | There are no entries in the table at the moment, only a definition. You can view definition with this command: 36 | 37 | .. code:: sql 38 | 39 | new_db.db> .schema switch 40 | +-----------------------------------------------------------------------------------------------+ 41 | | sql | 42 | +-----------------------------------------------------------------------------------------------+ 43 | | CREATE TABLE switch (mac text not NULL primary key, hostname text, model text, location text) | 44 | +-----------------------------------------------------------------------------------------------+ 45 | Time: 0.037s 46 | 47 | -------------------------------------------------------------------------------- /docs/source/book/14_regex/spec_sym_sets.rst: -------------------------------------------------------------------------------- 1 | Character sets 2 | --------------- 3 | 4 | Python has special designations for character sets: 5 | 6 | * ``\d`` - any digit 7 | * ``\D`` - any non-numeric value 8 | * ``\s`` - whitespace character 9 | * ``\S`` - all except whitespace characters 10 | * ``\w`` - any letter, digit or underline character 11 | * ``\W`` - all except letter, digit or underline character 12 | 13 | .. note:: 14 | 15 | These are not all character sets that support Python. See 16 | `documentation `__ for details. 17 | 18 | Character sets allow you to write shorter expressions without having to list 19 | all necessary characters. 20 | For example, get time from log file string: 21 | 22 | .. code:: python 23 | 24 | In [1]: log = '*Jul 7 06:15:18.695: %LINEPROTO-5-UPDOWN: Line protocol on Interface Ethernet0/3, changed state to down' 25 | 26 | In [2]: re.search('\d\d:\d\d:\d\d', log).group() 27 | Out[2]: '06:15:18' 28 | 29 | Expression ``\d\d:\d\d:\d\d`` describes 3 pairs of numbers separated by colons. 30 | 31 | Getting MAC address from log message: 32 | 33 | .. code:: python 34 | 35 | In [3]: log2 = 'Jun 3 14:39:05.941: %SW_MATM-4-MACFLAP_NOTIF: Host f03a.b216.7ad7 in vlan 10 is flapping between port Gi0/5 and port Gi0/15' 36 | 37 | In [4]: re.search('\w\w\w\w\.\w\w\w\w\.\w\w\w\w', log2).group() 38 | Out[4]: 'f03a.b216.7ad7' 39 | 40 | Expression ``\w\w\w\w\.\w\w\w\w\.\w\w\w\w`` describes 12 letters or digits that 41 | are divided into three groups of four characters and separated by dot. 42 | 43 | Symbol groups are very convenient, but for now it is necessary to manually 44 | specify a character repetition. The following subsection covers repetition 45 | symbols which will simplify description of expressions. 46 | -------------------------------------------------------------------------------- /docs/source/book/05_basic_scripts/args.rst: -------------------------------------------------------------------------------- 1 | Passing arguments to the script (sys.argv) 2 | ------------------------------------------ 3 | 4 | Very often script solves some common problem. For example, script processes 5 | a configuration file. Of course, in this case you don't want to edit name of 6 | file every time with your hands in script. 7 | It will be much better to pass file name as script argument and then use already specified file. 8 | The sys module allows working with script arguments via argv. 9 | 10 | Example of access_template_argv.py: 11 | 12 | .. code:: python 13 | 14 | from sys import argv 15 | 16 | interface = argv[1] 17 | vlan = argv[2] 18 | 19 | access_template = ['switchport mode access', 20 | 'switchport access vlan {}', 21 | 'switchport nonegotiate', 22 | 'spanning-tree portfast', 23 | 'spanning-tree bpduguard enable'] 24 | 25 | print('interface {}'.format(interface)) 26 | print('\n'.join(access_template).format(vlan)) 27 | 28 | Script output: 29 | 30 | :: 31 | 32 | $ python access_template_argv.py Gi0/7 4 33 | interface Gi0/7 34 | switchport mode access 35 | switchport access vlan 4 36 | switchport nonegotiate 37 | spanning-tree portfast 38 | spanning-tree bpduguard enable 39 | 40 | Arguments that have been passed to script are substituted as values in template. 41 | Several points need to be clarified: 42 | 43 | * argv is a list 44 | * all arguments are in list and represented as strings 45 | * argv contains not only arguments that passed to script but also name of script itself 46 | 47 | In this case, argv list contains the following elements: 48 | 49 | :: 50 | 51 | ['access_template_argv.py', 'Gi0/7', '4'] 52 | 53 | First comes the name of script itself, then arguments in the same order. 54 | 55 | -------------------------------------------------------------------------------- /docs/source/book/25_db/sqlite3_connection_without_cursor.rst: -------------------------------------------------------------------------------- 1 | Using sqlite3 module without explicit cursor creation 2 | -------------------------------------------------------- 3 | 4 | Execute methods are available in Connection object and in Cursor object but 5 | ``fetch`` methods are only available in Cursor object. 6 | 7 | When using ``execute`` methods with Connection object, cursor is returned 8 | as a result of ``execute`` method. It can be used as an iterator and receive 9 | data without ``fetch`` methods. This allows you not to create cursor when 10 | working with sqlite3 module. 11 | 12 | Example of the resulting script (create_sw_inventory_ver1.py): 13 | 14 | .. code:: python 15 | 16 | import sqlite3 17 | 18 | 19 | data = [('0000.AAAA.CCCC', 'sw1', 'Cisco 3750', 'London, Green Str'), 20 | ('0000.BBBB.CCCC', 'sw2', 'Cisco 3780', 'London, Green Str'), 21 | ('0000.AAAA.DDDD', 'sw3', 'Cisco 2960', 'London, Green Str'), 22 | ('0011.AAAA.CCCC', 'sw4', 'Cisco 3750', 'London, Green Str')] 23 | 24 | 25 | con = sqlite3.connect('sw_inventory2.db') 26 | 27 | con.execute('''create table switch 28 | (mac text not NULL primary key, hostname text, model text, location text)''' 29 | ) 30 | 31 | query = 'INSERT into switch values (?, ?, ?, ?)' 32 | con.executemany(query, data) 33 | con.commit() 34 | 35 | for row in con.execute('select * from switch'): 36 | print(row) 37 | 38 | con.close() 39 | 40 | The result will be: 41 | 42 | :: 43 | 44 | $ python create_sw_inventory_ver1.py 45 | ('0000.AAAA.CCCC', 'sw1', 'Cisco 3750', 'London, Green Str') 46 | ('0000.BBBB.CCCC', 'sw2', 'Cisco 3780', 'London, Green Str') 47 | ('0000.AAAA.DDDD', 'sw3', 'Cisco 2960', 'London, Green Str') 48 | ('0011.AAAA.CCCC', 'sw4', 'Cisco 3750', 'London, Green Str') 49 | 50 | -------------------------------------------------------------------------------- /docs/source/book/25_db/sqlite3_cursor_as_iterator.rst: -------------------------------------------------------------------------------- 1 | Cursor as iterator 2 | ------------------- 3 | 4 | If you want to process the resulting strings, use cursor as an iterator. It is 5 | not necessary to use fetch methods. 6 | 7 | If you use ``execute`` methods, the cursor is returned. Since cursor can 8 | be used as an iterator you can use it, for example, in ``for`` loop: 9 | 10 | .. code:: python 11 | 12 | In [34]: result = cursor.execute('select * from switch') 13 | 14 | In [35]: for row in result: 15 | ...: print(row) 16 | ...: 17 | ('0000.AAAA.CCCC', 'sw1', 'Cisco 3750', 'London, Green Str') 18 | ('0000.BBBB.CCCC', 'sw2', 'Cisco 3780', 'London, Green Str') 19 | ('0000.AAAA.DDDD', 'sw3', 'Cisco 2960', 'London, Green Str') 20 | ('0011.AAAA.CCCC', 'sw4', 'Cisco 3750', 'London, Green Str') 21 | ('0000.1111.0001', 'sw5', 'Cisco 3750', 'London, Green Str') 22 | ('0000.1111.0002', 'sw6', 'Cisco 3750', 'London, Green Str') 23 | ('0000.1111.0003', 'sw7', 'Cisco 3750', 'London, Green Str') 24 | ('0000.1111.0004', 'sw8', 'Cisco 3750', 'London, Green Str') 25 | 26 | The same option will work without assigning a variable: 27 | 28 | .. code:: python 29 | 30 | In [36]: for row in cursor.execute('select * from switch'): 31 | ...: print(row) 32 | ...: 33 | ('0000.AAAA.CCCC', 'sw1', 'Cisco 3750', 'London, Green Str') 34 | ('0000.BBBB.CCCC', 'sw2', 'Cisco 3780', 'London, Green Str') 35 | ('0000.AAAA.DDDD', 'sw3', 'Cisco 2960', 'London, Green Str') 36 | ('0011.AAAA.CCCC', 'sw4', 'Cisco 3750', 'London, Green Str') 37 | ('0000.1111.0001', 'sw5', 'Cisco 3750', 'London, Green Str') 38 | ('0000.1111.0002', 'sw6', 'Cisco 3750', 'London, Green Str') 39 | ('0000.1111.0003', 'sw7', 'Cisco 3750', 'London, Green Str') 40 | ('0000.1111.0004', 'sw8', 'Cisco 3750', 'London, Green Str') 41 | 42 | -------------------------------------------------------------------------------- /docs/source/book/22_oop_basics/class_example.rst: -------------------------------------------------------------------------------- 1 | Class example 2 | ~~~~~~~~~~~~~ 3 | 4 | The class that describes the network: 5 | 6 | .. code:: python 7 | 8 | class Network: 9 | def __init__(self, network): 10 | self.network = network 11 | self.hosts = tuple(str(ip) for ip in ipaddress.ip_network(network).hosts()) 12 | self.allocated = [] 13 | 14 | def allocate(self, ip): 15 | if ip in self.hosts: 16 | if ip not in self.allocated: 17 | self.allocated.append(ip) 18 | else: 19 | raise ValueError(f"IP address {ip} is already in the allocated list") 20 | else: 21 | raise ValueError(f"IP address {ip} does not belong to {self.network}") 22 | 23 | Using the class: 24 | 25 | .. code:: python 26 | 27 | In [2]: net1 = Network("10.1.1.0/29") 28 | 29 | In [3]: net1.allocate("10.1.1.1") 30 | 31 | In [4]: net1.allocate("10.1.1.2") 32 | 33 | In [5]: net1.allocated 34 | Out[5]: ['10.1.1.1', '10.1.1.2'] 35 | 36 | In [6]: net1.allocate("10.1.1.100") 37 | --------------------------------------------------------------------------- 38 | ValueError Traceback (most recent call last) 39 | in 40 | ----> 1 net1.allocate("10.1.1.100") 41 | 42 | in allocate(self, ip) 43 | 12 raise ValueError(f"IP address {ip} is already in the allocated list") 44 | 13 else: 45 | ---> 14 raise ValueError(f"IP address {ip} does not belong to {self.network}") 46 | 15 47 | 48 | ValueError: IP address 10.1.1.100 does not belong to 10.1.1.0/29 49 | 50 | In [7]: net1.hosts 51 | Out[7]: ('10.1.1.1', '10.1.1.2', '10.1.1.3', '10.1.1.4', '10.1.1.5', '10.1.1.6') 52 | 53 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Python for network engineers 2 | ============================ 3 | 4 | The book covers Python basics with examples and tasks built around networking topics. 5 | 6 | On the one hand, this book is basic enough to be mastered by anyone, and on 7 | the other hand, covers all the main topics that will allow you to further 8 | grow on your own. This book is not intended to be an in-depth look at Python. 9 | The purpose of this book is to explain the basics of Python in clear language 10 | and provide an understanding of the necessary tools for practical use. 11 | Everything in the book is focused on network equipment and interaction with it. 12 | This immediately makes it possible to use the knowledge gained in the daily 13 | work of network engineers. All examples are shown using Cisco equipment 14 | as an example, but of course they apply to any other equipment. 15 | 16 | .. note:: 17 | 18 | This book covers Python 3.7. 19 | 20 | `The book was written by Natasha Samoylenko `__. `Translated from Russian by Aidar Khairullin `__. 21 | 22 | 23 | .. toctree:: 24 | :maxdepth: 2 25 | :hidden: 26 | 27 | download 28 | intro_index 29 | book_links 30 | book/Part_I 31 | book/Part_II 32 | book/Part_III 33 | book/Part_IV 34 | book/Part_V 35 | book/Part_VI 36 | book/Part_VII 37 | book/Part_VIII 38 | resources/README 39 | testimonials 40 | 41 | 42 | .. toctree:: 43 | :caption: Links 44 | :maxdepth: 1 45 | :hidden: 46 | 47 | Examples and tasks 48 | Answers 49 | Ask a Question 50 | 51 | .. toctree:: 52 | :caption: Languages 53 | :maxdepth: 1 54 | 55 | Ukrainian 56 | -------------------------------------------------------------------------------- /docs/source/book/02_git_github/git_github_auth.rst: -------------------------------------------------------------------------------- 1 | Github authentication 2 | ~~~~~~~~~~~~~~~~~~~~~~~~ 3 | 4 | In order to start working with GitHub, you need to 5 | `register `__ on it. It is better to use SSH key 6 | authentication to work safely with Github. 7 | 8 | 9 | Generation of a new SSH key (use e-mail that is linked to Github): 10 | 11 | :: 12 | 13 | $ ssh-keygen -t rsa -b 4096 -C "github_email@gmail.com" 14 | 15 | On all questions, just press Enter. It is more secure to use passphrase 16 | but if you press Enter when asked then passphrase will not be requested 17 | from you permanently during operations with repository. 18 | 19 | Start SSH agent: 20 | 21 | :: 22 | 23 | $ eval "$(ssh-agent -s)" 24 | 25 | Add key to SSH agent: 26 | 27 | :: 28 | 29 | $ ssh-add ~/.ssh/id_rsa 30 | 31 | Add SSH key to Github 32 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 33 | 34 | To add a key you have to copy it. 35 | For example, you can display key with cat to copy it: 36 | 37 | :: 38 | 39 | $ cat ~/.ssh/id_rsa.pub 40 | 41 | After copying, go to Github. When you are on any Github page, in upper 42 | right-hand corner click on picture of your profile and select "Settings" 43 | in drop down list. In list on the left, select field "SSH and GPG keys". 44 | Then press "New SSH key" and in "Title" field write key name (for example 45 | "Home") and in field "Key" insert the content that was copied from 46 | file ~/. ssh/id_rsa.pub. 47 | 48 | .. note:: 49 | If Github requests a password, enter your account password on Github. 50 | 51 | To check if everything has been successful, try executing command 52 | ``ssh -T git@github.com``. 53 | 54 | The output should be as follows: 55 | 56 | :: 57 | 58 | $ ssh -T git@github.com 59 | Hi username! You've successfully authenticated, but GitHub does not provide shell access. 60 | 61 | Now you are ready to work with Git and Github. 62 | -------------------------------------------------------------------------------- /docs/source/book/19_concurrent_connections/further_reading.rst: -------------------------------------------------------------------------------- 1 | Further reading 2 | ------------------------ 3 | 4 | Python documentation: 5 | 6 | - `concurrent.futures — Launching parallel 7 | tasks `__ 8 | - `threading `__ 9 | - `multiprocessing `__ 10 | - `queue `__ 11 | - `PEP 3148 `__ 12 | - `PyMOTW. concurrent.futures — Manage Pools of Concurrent 13 | Tasks `__ 14 | 15 | GIL 16 | ~~~ 17 | 18 | - `Can't we get rid of the Global Interpreter 19 | Lock? `__ 20 | - `Understanding the Python GIL `__ 21 | - `Python threads and the 22 | GIL `__ 23 | 24 | concurrent.futures 25 | ~~~~~~~~~~~~~~~~~~ 26 | 27 | - `A quick introduction to the concurrent.futures 28 | module `__ 29 | - `Python - paralellizing CPU-bound tasks with 30 | concurrent.futures `__ 31 | - `concurrent.futures in Python 32 | 3 `__ 33 | 34 | Useful questions and answers on stackoverflow 35 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 36 | 37 | - `How many processes should I run in 38 | parallel? `__ 39 | - `How many threads is too 40 | many? `__ 41 | 42 | -------------------------------------------------------------------------------- /docs/source/book/01_intro/pip.rst: -------------------------------------------------------------------------------- 1 | Package management system Pip 2 | =============================== 3 | 4 | Pip will be used to install Python packages. It is a package management system 5 | used to install packages from Python Package Index (Pypi). Most likely, if you 6 | already have Python installed, pip is installed. 7 | 8 | Check pip version: 9 | 10 | :: 11 | 12 | $ pip --version 13 | pip 19.1.1 from /home/vagrant/venv/pyneng-py3-7/lib/python3.7/site-packages/pip (python 3.7) 14 | 15 | 16 | If command failed, pip is not installed. Pip installation is described in `documentation `__ 17 | 18 | Module installation 19 | ^^^^^^^^^^^^^^^^^ 20 | 21 | Command to install modules ``pip install``: 22 | 23 | :: 24 | 25 | $ pip install tabulate 26 | 27 | To delete package: 28 | 29 | :: 30 | 31 | $ pip uninstall tabulate 32 | 33 | In addition, it is sometimes necessary to update package: 34 | 35 | :: 36 | 37 | $ pip install --upgrade tabulate 38 | 39 | pip or pip3 40 | ^^^^^^^^^^^^ 41 | 42 | Depending on how Python is installed and configured in system it may be 43 | necessary to use pip3 instead of pip. To check which option is used, 44 | you should execute command ``pip --version``. 45 | 46 | A version where pip corresponds to Python 2.7: 47 | 48 | :: 49 | 50 | $ pip --version 51 | pip 9.0.1 from /usr/local/lib/python2.7/dist-packages (python 2.7) 52 | 53 | A version where pip3 corresponds to 3.7: 54 | 55 | :: 56 | 57 | $ pip3 --version 58 | pip 19.1.1 from /home/vagrant/venv/pyneng-py3-7/lib/python3.7/site-packages/pip (python 3.7) 59 | 60 | 61 | If system uses pip3, then every time a Python module is installed in book it 62 | will be necessary to replace pip with pip3. 63 | 64 | Alternatively, call pip: 65 | 66 | :: 67 | 68 | $ python3.7 -m pip install tabulate 69 | 70 | Thus, it is always clear for which version of Python the package is installed. 71 | -------------------------------------------------------------------------------- /docs/source/book/20_jinja2/syntax_variables.rst: -------------------------------------------------------------------------------- 1 | Variables 2 | ---------- 3 | 4 | Variables in template are given in double curly braces: 5 | 6 | :: 7 | 8 | hostname {{ name }} 9 | 10 | interface Loopback0 11 | ip address 10.0.0.{{ id }} 255.255.255.255 12 | 13 | Variable values are set based on dictionary that is passed to template. 14 | 15 | Variable that is passed on in a dictionary may not only be a number or a string, 16 | but also for example, a list or a dictionary. Inside template, you can refer 17 | to the item by number or key. 18 | 19 | Template example templates/variables.txt with usage of different variable variants: 20 | 21 | :: 22 | 23 | hostname {{ name }} 24 | 25 | interface Loopback0 26 | ip address 10.0.0.{{ id }} 255.255.255.255 27 | 28 | vlan {{ vlans[0] }} 29 | 30 | router ospf 1 31 | router-id 10.0.0.{{ id }} 32 | auto-cost reference-bandwidth 10000 33 | network {{ ospf.network }} area {{ ospf['area'] }} 34 | 35 | And corresponding data_files/vars.yml file with variables: 36 | 37 | :: 38 | 39 | id: 3 40 | name: R3 41 | vlans: 42 | - 10 43 | - 20 44 | - 30 45 | ospf: 46 | network: 10.0.1.0 0.0.0.255 47 | area: 0 48 | 49 | Note the use of vlans variable in template: since vlans variable is a list, 50 | you can specify which item from list we need 51 | 52 | If a dictionary is passed (as in case of ospf variable), you can refer to 53 | dictionary objects inside template using one of the variants: 54 | ``ospf.network or ospf['network']`` 55 | 56 | The result will be: 57 | 58 | :: 59 | 60 | $ python cfg_gen.py templates/variables.txt data_files/vars.yml 61 | hostname R3 62 | 63 | interface Loopback0 64 | ip address 10.0.0.3 255.255.255.255 65 | 66 | vlan 10 67 | 68 | router ospf 1 69 | router-id 10.0.0.3 70 | auto-cost reference-bandwidth 10000 71 | network 10.0.1.0 0.0.0.255 area 0 72 | 73 | -------------------------------------------------------------------------------- /docs/source/book/09_functions/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _functions_index: 6 | 7 | 9. Functions 8 | ============================ 9 | 10 | Function: 11 | 12 | * has a name to run this code block as many times as you want 13 | 14 | * launch of function code is called a function call 15 | 16 | * function parameters are usually defined when creating a function. 17 | 18 | * function parameters determine which arguments a function can accept 19 | * arguments can be passed to functions 20 | * function code will be executed taking into account the specified arguments 21 | 22 | **What are functions for?** 23 | 24 | Typically, problems that code solves are very similar and often have something in common. 25 | For example, when working with configuration files each time it is necessary to perform such actions: 26 | 27 | * file opening 28 | * deletion (or skipping) of lines starting with exclamation mark (for Cisco) 29 | * deleting (or skipping) empty lines 30 | * deleting new line characters at the end of lines 31 | * converting the result to a list 32 | 33 | Beyond that, actions can vary depending on what needs to be done. 34 | 35 | Often there's a piece of code that repeats itself. Of course, you can copy 36 | it from one script to another. But this is very inconvenient because when 37 | you change code you have to update it in all files in which it is copied. 38 | 39 | It is much easier and more accurate to put this code into a function (it can also be several functions). 40 | And then you will call this function - in this file or another one. 41 | This section discusses when a function is in the same file. 42 | And in :ref:`modules_index` we will see how to reuse objects that are in other scripts. 43 | 44 | .. toctree:: 45 | :maxdepth: 1 46 | :hidden: 47 | 48 | create_func 49 | namespace 50 | func_params_args 51 | func_unpacking_and_var_args_example 52 | further_reading 53 | ../../exercises/09_exercises 54 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/tuple.rst: -------------------------------------------------------------------------------- 1 | Tuple 2 | -------------- 3 | 4 | 5 | Tuple in Python is: 6 | 7 | * a sequence of elements separated by a comma and enclosed in parentheses 8 | * immutable ordered data type 9 | 10 | Roughly speaking, a tuple is a list that can't be changed. We can say that 11 | the tuple has read-only permissions. 12 | It could be a defense against accidental change. 13 | 14 | Create an empty tuple: 15 | 16 | .. code:: python 17 | 18 | In [1]: tuple1 = tuple() 19 | 20 | In [2]: print(tuple1) 21 | () 22 | 23 | Tuple with one element (note the comma): 24 | 25 | .. code:: python 26 | 27 | In [3]: tuple2 = ('password',) 28 | 29 | Tuple from list: 30 | 31 | .. code:: python 32 | 33 | In [4]: list_keys = ['hostname', 'location', 'vendor', 'model', 'ios', 'ip'] 34 | 35 | In [5]: tuple_keys = tuple(list_keys) 36 | 37 | In [6]: tuple_keys 38 | Out[6]: ('hostname', 'location', 'vendor', 'model', 'ios', 'ip') 39 | 40 | Objects in tuple can be accessed as well as objects in list, by order number: 41 | 42 | .. code:: python 43 | 44 | In [7]: tuple_keys[0] 45 | Out[7]: 'hostname' 46 | 47 | But since tuple is immutable you cannot assign a new value: 48 | 49 | .. code:: python 50 | 51 | In [8]: tuple_keys[1] = 'test' 52 | --------------------------------------------------------------------------- 53 | TypeError Traceback (most recent call last) 54 | in () 55 | ----> 1 tuple_keys[1] = 'test' 56 | 57 | TypeError: 'tuple' object does not support item assignment 58 | 59 | Function ``sorted`` sorts tuple elements in ascending order and returns a new 60 | list with sorted elements: 61 | 62 | .. code:: python 63 | 64 | 65 | In [2]: tuple_keys = ('hostname', 'location', 'vendor', 'model', 'ios', 'ip') 66 | 67 | In [3]: sorted(tuple_keys) 68 | Out[3]: ['hostname', 'ios', 'ip', 'location', 'model', 'vendor'] 69 | 70 | -------------------------------------------------------------------------------- /docs/source/book/02_git_github/git_basics_additional.rst: -------------------------------------------------------------------------------- 1 | Additional features 2 | ^^^^^^^^^^^^^^^^^^^ 3 | 4 | git diff 5 | '''''''' 6 | 7 | Command ``git diff`` allows you to see the difference between different states. 8 | For example, README and .gitignore files have been changed in repository. 9 | 10 | Command ``git status`` shows that both files have been changed 11 | 12 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_status_5.png 13 | 14 | Command ``git diff`` command shows what changes have been made since last commit 15 | 16 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_diff.png 17 | 18 | If you add changes made to staging via ``git add`` command and run ``git diff`` again, it will show nothing 19 | 20 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_add_git_diff.png 21 | 22 | To show the difference between staging and last commit, add parameter ``--staged`` 23 | 24 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_diff_staged.png 25 | 26 | Commit changes 27 | 28 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_commit_2.png 29 | 30 | git log 31 | ''''''' 32 | 33 | Command ``git log`` command shows when last changes were made 34 | 35 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_log.png 36 | 37 | By default, command displays all commits starting from the nearest time. With 38 | help of additional parameters it is possible not only to look at information 39 | about commits but also what changes have been made. 40 | 41 | Flag ``-p`` allows you to display the differences that have been made by each commit 42 | 43 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_log_p.png 44 | 45 | Shorter output option can be displayed with flag ``--stat`` 46 | 47 | .. figure:: https://raw.githubusercontent.com/natenka/PyNEng/master/images/git/git_log_stat.png 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/source/book/20_jinja2/syntax_for.rst: -------------------------------------------------------------------------------- 1 | Loop for 2 | -------- 3 | 4 | Loop ``for`` allows you to walk through sequence of elements. 5 | 6 | Loop ``for`` must be written inside ``{% %}``. 7 | Furthermore, the end of the loop must be explicitly indicated: 8 | 9 | :: 10 | 11 | {% for vlan in vlans %} 12 | vlan {{ vlan }} 13 | {% endfor %} 14 | 15 | Template example templates/for.txt using a loop: 16 | 17 | :: 18 | 19 | hostname {{ name }} 20 | 21 | interface Loopback0 22 | ip address 10.0.0.{{ id }} 255.255.255.255 23 | 24 | {% for vlan, name in vlans.items() %} 25 | vlan {{ vlan }} 26 | name {{ name }} 27 | {% endfor %} 28 | 29 | router ospf 1 30 | router-id 10.0.0.{{ id }} 31 | auto-cost reference-bandwidth 10000 32 | {% for networks in ospf %} 33 | network {{ networks.network }} area {{ networks.area }} 34 | {% endfor %} 35 | 36 | File data_files/for.yml with variables: 37 | 38 | .. code:: yaml 39 | 40 | id: 3 41 | name: R3 42 | vlans: 43 | 10: Marketing 44 | 20: Voice 45 | 30: Management 46 | ospf: 47 | - network: 10.0.1.0 0.0.0.255 48 | area: 0 49 | - network: 10.0.2.0 0.0.0.255 50 | area: 2 51 | - network: 10.1.1.0 0.0.0.255 52 | area: 0 53 | 54 | In ``for``, it is possible to go through both the list elements (for example, 55 | ospf list) and the dictionary (vlans dictionary). And similarly, through any sequence. 56 | 57 | The result will be: 58 | 59 | :: 60 | 61 | $ python cfg_gen.py templates/for.txt data_files/for.yml 62 | hostname R3 63 | 64 | interface Loopback0 65 | ip address 10.0.0.3 255.255.255.255 66 | 67 | vlan 10 68 | name Marketing 69 | vlan 20 70 | name Voice 71 | vlan 30 72 | name Management 73 | 74 | router ospf 1 75 | router-id 10.0.0.3 76 | auto-cost reference-bandwidth 10000 77 | network 10.0.1.0 0.0.0.255 area 0 78 | network 10.0.2.0 0.0.0.255 area 2 79 | network 10.1.1.0 0.0.0.255 area 0 80 | 81 | -------------------------------------------------------------------------------- /docs/source/book/25_db/alter.rst: -------------------------------------------------------------------------------- 1 | ALTER 2 | ~~~~~ 3 | 4 | ALTER TABKE statement allows you to change an existing table: add new columns or rename the table. 5 | 6 | Add new fields to the table: 7 | 8 | * mngmt_ip - switch IP address in management VLAN 9 | * mngmt_vid - VLAN ID of management VLAN 10 | 11 | Adding entries using ALTER TABLE: 12 | 13 | .. code:: sql 14 | 15 | new_db.db> ALTER table switch ADD COLUMN mngmt_ip text; 16 | You're about to run a destructive command. 17 | Do you want to proceed? (y/n): y 18 | Your call! 19 | Query OK, 0 rows affected 20 | Time: 0.009s 21 | 22 | new_db.db> ALTER table switch ADD COLUMN mngmt_vid integer; 23 | You're about to run a destructive command. 24 | Do you want to proceed? (y/n): y 25 | Your call! 26 | Query OK, 0 rows affected 27 | Time: 0.010s 28 | 29 | Now table looks like this (new fields are set to NULL): 30 | 31 | .. code:: sql 32 | 33 | new_db.db> SELECT * from switch; 34 | +----------------+----------+------------+-------------------+----------+-----------+ 35 | | mac | hostname | model | location | mngmt_ip | mngmt_vid | 36 | +----------------+----------+------------+-------------------+----------+-----------+ 37 | | 0010.A1AA.C1CC | sw1 | Cisco 3750 | London, Green Str | | | 38 | | 0020.A2AA.C2CC | sw2 | Cisco 3850 | London, Green Str | | | 39 | | 0030.A3AA.C1CC | sw3 | Cisco 3750 | London, Green Str | | | 40 | | 0040.A4AA.C2CC | sw4 | Cisco 3850 | London, Green Str | | | 41 | | 0050.A5AA.C3CC | sw5 | Cisco 3850 | London, Green Str | | | 42 | | 0060.A6AA.C4CC | sw6 | C3750 | London, Green Str | | | 43 | | 0070.A7AA.C5CC | sw7 | Cisco 3650 | London, Green Str | | | 44 | +----------------+----------+------------+-------------------+----------+-----------+ 45 | 7 rows in set 46 | Time: 0.034s 47 | 48 | -------------------------------------------------------------------------------- /docs/source/book/14_regex/non-capturing_groups.rst: -------------------------------------------------------------------------------- 1 | Non-capturing group 2 | ------------------ 3 | 4 | By default, everything that fell into the group is remembered. It's called a 5 | capturing group. 6 | 7 | Sometimes parentheses are needed to indicate a part of expression that repeats. 8 | And, in doing so, you don't need to remember an expression. 9 | 10 | For example, get a MAC address, VLAN and ports from log message: 11 | 12 | .. code:: python 13 | 14 | In [1]: log = 'Jun 3 14:39:05.941: %SW_MATM-4-MACFLAP_NOTIF: Host f03a.b216.7ad7 in vlan 10 is flapping between port Gi0/5 and port Gi0/15' 15 | 16 | A regex that describes substrings: 17 | 18 | .. code:: python 19 | 20 | In [2]: match = re.search('((\w{4}\.){2}\w{4}).+vlan (\d+).+port (\S+).+port (\S+)', log) 21 | 22 | Expression consists of the following parts: 23 | 24 | * ``((\w{4}\.){2}\w{4})`` - MAC address gets here 25 | * ``\w{4}\.`` - this part describes 4 letters or digits and a dot 26 | * ``(\w{4}\.){2}`` - here parentheses are used to indicate that 4 letters or digits and a dot are repeated twice 27 | * ``\w{4}`` - then 4 letters or numbers 28 | * ``.+vlan (\d+)`` - VLAN number falls into the group 29 | * ``.+port (\S+)`` - first interface 30 | * ``.+port (\S+)`` - second interface 31 | 32 | Method ``groups`` returns: 33 | 34 | .. code:: python 35 | 36 | In [3]: match.groups() 37 | Out[3]: ('f03a.b216.7ad7', 'b216.', '10', 'Gi0/5', 'Gi0/15') 38 | 39 | The second element is essentially superfluous. It appeared in the output because 40 | of parentheses in expression ``(\w{4}\.){2}``. 41 | 42 | In this case, you need to disable capture in the group. This is done by 43 | adding ``?:`` after the group's opening parenthesis. 44 | 45 | Now the expression looks like this: 46 | 47 | .. code:: python 48 | 49 | In [4]: match = re.search('((?:\w{4}\.){2}\w{4}).+vlan (\d+).+port (\S+).+port (\S+)', log) 50 | 51 | Accordingly, ``groups`` method returns: 52 | 53 | .. code:: python 54 | 55 | In [5]: match.groups() 56 | Out[5]: ('f03a.b216.7ad7', '10', 'Gi0/5', 'Gi0/15') 57 | 58 | -------------------------------------------------------------------------------- /docs/source/book/additional_info/pyneng_on_linux.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _additional_info_pyneng_linux: 6 | 7 | Preparing Linux 8 | =============== 9 | 10 | Installing Python 3.7 on Debian 9 11 | --------------------------------- 12 | 13 | If you are installing on a clean OS, it is best to install these packages: 14 | 15 | :: 16 | 17 | sudo apt-get install build-essential checkinstall 18 | sudo apt-get install libreadline-gplv2-dev libncursesw5-dev libssl-dev 19 | sudo apt-get install libsqlite3-dev tk-dev libgdbm-dev libc6-dev libbz2-dev libffi-dev 20 | 21 | Installing Python 3.7 22 | 23 | :: 24 | 25 | wget https://www.python.org/ftp/python/3.7.3/Python-3.7.3.tgz 26 | tar xvf Python-3.7.3.tgz 27 | cd Python-3.7.3 28 | ./configure --enable-optimizations --enable-loadable-sqlite-extensions 29 | sudo make altinstall 30 | 31 | After that, you can create a `virtual environment `__. 32 | 33 | Virtual environment 34 | ------------------- 35 | 36 | Installing virtualenvwrapper with pip: 37 | 38 | :: 39 | 40 | python3.7 -m pip install virtualenvwrapper 41 | 42 | After installation, in ``~/.bashrc`` file in current user's home folder, you need 43 | to add several lines: 44 | 45 | :: 46 | 47 | export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3.7 48 | export WORKON_HOME=~/venv 49 | 50 | . /usr/local/bin/virtualenvwrapper.sh 51 | 52 | Restart command interpreter: 53 | 54 | :: 55 | 56 | exec bash 57 | 58 | Create a virtual environment using Python 3.7 (the same command will take you to a virtual environment): 59 | 60 | :: 61 | 62 | mkvirtualenv --python=/usr/local/bin/python3.7 pyneng-py3 63 | 64 | 65 | List of modules that need to be installed to complete tasks 66 | ----------------------------------------------------------- 67 | 68 | :: 69 | 70 | pip install pytest pytest-clarity pyyaml tabulate jinja2 textfsm pexpect netmiko 71 | 72 | You also need to install graphviz on the OS (example for debian): 73 | 74 | :: 75 | 76 | apt-get install graphviz 77 | 78 | -------------------------------------------------------------------------------- /docs/source/book/05_basic_scripts/user_input.rst: -------------------------------------------------------------------------------- 1 | User input 2 | ----------------------------- 3 | 4 | Sometimes it is necessary to get information from user. For example, request a password. 5 | The ``input`` function is used to get information from the user: 6 | 7 | .. code:: python 8 | 9 | In [1]: print(input('What is your faivorite routing protocol? ')) 10 | What is your faivorite routing protocol? OSPF 11 | OSPF 12 | 13 | In this case, information is immediately displayed to user, but in addition, information entered by user can be stored in a variable and can be used later in script. 14 | 15 | .. code:: python 16 | 17 | In [2]: protocol = input('What is your faivorite routing protocol? ') 18 | What is your faivorite routing protocol? OSPF 19 | 20 | In [3]: print(protocol) 21 | OSPF 22 | 23 | In parentheses, a question is usually written that specifies what information needs to be entered. 24 | A script that asks the user for information using input (file access_template_input.py): 25 | 26 | .. code:: python 27 | 28 | interface = input('Enter interface type and number: ') 29 | vlan = input('Enter VLAN number: ') 30 | 31 | access_template = ['switchport mode access', 32 | 'switchport access vlan {}', 33 | 'switchport nonegotiate', 34 | 'spanning-tree portfast', 35 | 'spanning-tree bpduguard enable'] 36 | 37 | print('\n' + '-' * 30) 38 | print('interface {}'.format(interface)) 39 | print('\n'.join(access_template).format(vlan)) 40 | 41 | First two lines request information from user. 42 | Line ``print('\n' + '-' * 30)`` is used to visually separate information request from the output. 43 | 44 | Script output: 45 | 46 | :: 47 | 48 | $ python access_template_input.py 49 | Enter interface type and number: Gi0/3 50 | Enter VLAN number: 55 51 | 52 | ------------------------------ 53 | interface Gi0/3 54 | switchport mode access 55 | switchport access vlan 55 56 | switchport nonegotiate 57 | spanning-tree portfast 58 | spanning-tree bpduguard enable 59 | 60 | -------------------------------------------------------------------------------- /docs/source/book/15_module_re/split.rst: -------------------------------------------------------------------------------- 1 | Function re.split 2 | ---------------- 3 | 4 | Function ``split`` works similary to ``split`` method in strings, 5 | but in ``re.split`` function you can use regular expressions which 6 | means dividing a string into parts using more complex conditions. 7 | 8 | For example, ``ospf_route`` string should be split by spaces 9 | (as in ``str.split`` method): 10 | 11 | .. code:: python 12 | 13 | In [1]: ospf_route = 'O 10.0.24.0/24 [110/41] via 10.0.13.3, 3d18h, FastEthernet0/0' 14 | 15 | In [2]: re.split(r' +', ospf_route) 16 | Out[2]: 17 | ['O', 18 | '10.0.24.0/24', 19 | '[110/41]', 20 | 'via', 21 | '10.0.13.3,', 22 | '3d18h,', 23 | 'FastEthernet0/0'] 24 | 25 | Similarly, commas can be removed: 26 | 27 | .. code:: python 28 | 29 | In [3]: re.split(r'[ ,]+', ospf_route) 30 | Out[3]: 31 | ['O', 32 | '10.0.24.0/24', 33 | '[110/41]', 34 | 'via', 35 | '10.0.13.3', 36 | '3d18h', 37 | 'FastEthernet0/0'] 38 | 39 | And if necessary, get rid of square brackets: 40 | 41 | .. code:: python 42 | 43 | In [4]: re.split(r'[ ,\[\]]+', ospf_route) 44 | Out[4]: ['O', '10.0.24.0/24', '110/41', 'via', '10.0.13.3', '3d18h', 'FastEthernet0/0'] 45 | 46 | Function ``split`` has a peculiarity of working with groups (expressions in 47 | parentheses). If you specify the same expression with parentheses, the resulting 48 | list will include separators. 49 | 50 | For example, word via is specified as a separator: 51 | 52 | .. code:: python 53 | 54 | In [5]: re.split(r'(via|[ ,\[\]])+', ospf_route) 55 | Out[5]: 56 | ['O', 57 | ' ', 58 | '10.0.24.0/24', 59 | '[', 60 | '110/41', 61 | ' ', 62 | '10.0.13.3', 63 | ' ', 64 | '3d18h', 65 | ' ', 66 | 'FastEthernet0/0'] 67 | 68 | To disable such behavior you should make a noncapture group. That is, 69 | disable capturing of group elements: 70 | 71 | .. code:: python 72 | 73 | In [6]: re.split(r'(?:via|[ ,\[\]])+', ospf_route) 74 | Out[6]: ['O', '10.0.24.0/24', '110/41', '10.0.13.3', '3d18h', 'FastEthernet0/0'] 75 | 76 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/method_chaining.rst: -------------------------------------------------------------------------------- 1 | Method chaining 2 | =============== 3 | 4 | Often, you need to perform several operations with data, for example: 5 | 6 | .. code:: python 7 | 8 | In [1]: line = "switchport trunk allowed vlan 10,20,30" 9 | 10 | In [2]: words = line.split() 11 | 12 | In [3]: words 13 | Out[3]: ['switchport', 'trunk', 'allowed', 'vlan', '10,20,30'] 14 | 15 | In [4]: vlans_str = words[-1] 16 | 17 | In [5]: vlans_str 18 | Out[5]: '10,20,30' 19 | 20 | In [6]: vlans = vlans_str.split(",") 21 | 22 | In [7]: vlans 23 | Out[7]: ['10', '20', '30'] 24 | 25 | In the script: 26 | 27 | .. code:: python 28 | 29 | line = "switchport trunk allowed vlan 10,20,30" 30 | words = line.split() 31 | vlans_str = words[-1] 32 | vlans = vlans_str.split(",") 33 | print(vlans) 34 | 35 | In this case, variables are used to store the intermediate result 36 | and subsequent methods/actions are performed with the variable. 37 | This is a completely normal version of the code, especially at first when it's hard 38 | perceive more complex expressions. 39 | 40 | However, in Python, there are often expressions in which actions or methods 41 | are applied one after the other in one expression. 42 | For example, the previous code could be written like this: 43 | 44 | .. code:: python 45 | 46 | line = "switchport trunk allowed vlan 10,20,30" 47 | vlans = line.split()[-1].split(",") 48 | print(vlans) 49 | 50 | Since there are no expressions in parentheses that would indicate the priority of execution, 51 | everything is executed from left to right. 52 | 53 | 54 | First, ``line.split()`` is executed - we get the list, then to the resulting list 55 | applies ``[-1]`` - we get the last element of the list, the line ``10,20,30``. 56 | The method ``split(",")`` is applied to this line and as a result we get the list ``['10', '20', '30']``. 57 | 58 | 59 | The main nuance when writing such chains, the previous method/action should return something 60 | what the next method/action is waiting for. 61 | And it is imperative that something is returned, otherwise there will be an error. 62 | -------------------------------------------------------------------------------- /docs/source/book/additional_info/naming_conventions/README.rst: -------------------------------------------------------------------------------- 1 | Naming convention 2 | -------------------- 3 | 4 | Python has certain objects naming convention 5 | 6 | In general, it is better to adhere to this convention. However, if a particular 7 | library or module uses different convention, it is worth following the style used in them. 8 | 9 | Not all rules are described in this section. More information can be found in PEP8 in 10 | `English `__ or 11 | `Russian `__. 12 | 13 | Variable names 14 | ~~~~~~~~~~~~~~~~ 15 | 16 | Variable names should not overlap with operators and names of modules or other 17 | reserved values. 18 | Variable names are usually written entirely in large or small letters. It is 19 | better to stick to one of option within a script/module/package. 20 | 21 | If variables are constants for module, it is better to use names written in capital letters: 22 | 23 | .. code:: python 24 | 25 | DB_NAME = 'dhcp_snooping.db' 26 | TESTING = True 27 | 28 | For ordinary variables it is better to use lower case names: 29 | 30 | .. code:: python 31 | 32 | db_name = 'dhcp_snooping.db' 33 | testing = True 34 | 35 | Module and package names 36 | ~~~~~~~~~~~~~~~~~~~~~~~ 37 | 38 | Names of modules and packages are given in small letters. 39 | 40 | Modules can use underscores to make names more understandable. For packages it 41 | is better to select short names. 42 | 43 | Function names 44 | ~~~~~~~~~~~~~ 45 | 46 | Function names are given in small letters with underscores between words. 47 | 48 | .. code:: python 49 | 50 | def ignore_command(command, ignore): 51 | 52 | ignore_command = False 53 | 54 | for word in ignore: 55 | if word in command: 56 | return True 57 | return ignore_command 58 | 59 | Class names 60 | ~~~~~~~~~~~~~ 61 | 62 | Class names are given with capital letters, no spaces. 63 | 64 | .. code:: python 65 | 66 | class CiscoSwitch: 67 | 68 | def __init__(self, name, vendor='cisco', model='3750'): 69 | self.name = name 70 | self.vendor = vendor 71 | self.model = model 72 | 73 | -------------------------------------------------------------------------------- /docs/source/book/10_useful_functions/all_any.rst: -------------------------------------------------------------------------------- 1 | all 2 | ----------- 3 | 4 | Function ``all`` returns True if all elements are true (or object is empty). 5 | 6 | .. code:: python 7 | 8 | In [1]: all([False, True, True]) 9 | Out[1]: False 10 | 11 | In [2]: all([True, True, True]) 12 | Out[2]: True 13 | 14 | In [3]: all([]) 15 | Out[3]: True 16 | 17 | For example, it is possible to check that all octets in an IP address are numbers: 18 | 19 | .. code:: python 20 | 21 | In [4]: ip = '10.0.1.1' 22 | 23 | In [5]: all([i.isdigit() for i in ip.split('.')]) 24 | Out[5]: True 25 | 26 | In [6]: all([i.isdigit() for i in '10.1.1.a'.split('.')]) 27 | Out[6]: False 28 | 29 | any 30 | ----------- 31 | 32 | Function ``any`` returns True if at least one element is true. 33 | 34 | .. code:: python 35 | 36 | In [7]: any([False, True, True]) 37 | Out[7]: True 38 | 39 | In [8]: any([False, False, False]) 40 | Out[8]: False 41 | 42 | In [9]: any([]) 43 | Out[9]: False 44 | 45 | In [10]: any([i.isdigit() for i in '10.1.1.a'.split('.')]) 46 | Out[10]: True 47 | 48 | For example, with ``any`` you can replace ``ignore_command`` function: 49 | 50 | .. code:: python 51 | 52 | def ignore_command(command): 53 | ''' 54 | Function checks if command contains a word from ignore list. 55 | * command is a string. Command that need to be checked returns True 56 | * if command contains a word from ignore list, False - if not. 57 | ''' 58 | ignore = ['duplex', 'alias', 'Current configuration'] 59 | 60 | for word in ignore: 61 | if word in command: 62 | return True 63 | return False 64 | 65 | To this option: 66 | 67 | .. code:: python 68 | 69 | def ignore_command(command): 70 | ''' 71 | Function checks if command contains a word from ignore list. 72 | * command is a string. Command that need to be checked returns True 73 | * if command contains a word from ignore list, False - if not. 74 | ''' 75 | ignore = ['duplex', 'alias', 'Current configuration'] 76 | 77 | return any([word in command for word in ignore]) 78 | 79 | -------------------------------------------------------------------------------- /docs/source/book/18_ssh_telnet/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _ssh_telnet_index: 6 | 7 | 18. Connection to network devices 8 | ============================== 9 | 10 | This section discusses how to connect to network devices via: 11 | 12 | * SSH 13 | * Telnet 14 | 15 | Python has several modules that allow you to connect to network devices and execute commands: 16 | 17 | * ``pexpect`` - an implementation of ``expect`` in Python 18 | 19 | * this module allows working with any interactive session: ssh, telnet, sftp, etc. 20 | * in addition, it makes possible to execute different commands in OS (this can also be done with other modules) 21 | * while pexpect may be less user-friendly than other modules, it implements 22 | a more general functionality and allows it to be used in situations where other modules do not work 23 | 24 | * ``telnetlib`` - this module allows you connecting via Telnet 25 | 26 | * ``netmiko`` version >= 1.0 also has Telnet support, so if ``netmiko`` supports 27 | the network devices you use, it is more convenient to use it 28 | 29 | * ``paramiko`` - his module allows you connecting via SSHv2 30 | 31 | * it is more convenient to use than ``pexpect`` but with narrower functionality (only supports SSH) 32 | 33 | * ``netmiko`` - module that simplifies the use of paramiko for network devices 34 | 35 | * ``netmiko`` is a "wrapper" which is oriented to work with network devices 36 | 37 | * ``scrapli`` - is a module that allows you to connect to network equipment 38 | using Telnet, SSH or NETCONF 39 | 40 | 41 | This section covers all five modules and describes how to connect to several 42 | devices in parallel. Three routers are used in section examples. There are no 43 | requirements for them, only configured SSHv2 and Telnet. 44 | 45 | Parameters used in these section: 46 | 47 | * user: cisco 48 | * password: cisco 49 | * password for enable mode: cisco 50 | * SSH version 2, Telnet 51 | * IP addresses: 192.168.100.1, 192.168.100.2, 192.168.100.3 52 | 53 | .. toctree:: 54 | :maxdepth: 1 55 | :hidden: 56 | 57 | password 58 | pexpect 59 | telnetlib 60 | paramiko 61 | netmiko 62 | scrapli 63 | further_reading 64 | ../../exercises/18_exercises 65 | -------------------------------------------------------------------------------- /docs/source/book/07_files/close.rst: -------------------------------------------------------------------------------- 1 | File closing 2 | --------------- 3 | 4 | .. note:: 5 | In real life, the most common way to close files is use of ``with`` 6 | statement. It's much more convenient way than to close file explicitly. 7 | But since you can also find ``close`` method in life, this section discusses how to use it. 8 | 9 | After you finish working with file you have to close it. In some cases Python can close file itself. But it's best not to count on it and close file explicitly. 10 | 11 | ``close`` 12 | ^^^^^^^^^^^ 13 | 14 | Method close() met in `File writing `__ section. 15 | It was there to make sure that the content of file was written on disk. 16 | 17 | For this, Python has a separate ``flush`` method. 18 | But since in example with file writing there was no need to perform any more operations, file could be closed. 19 | 20 | Open the r1.txt file: 21 | 22 | .. code:: python 23 | 24 | In [1]: f = open('r1.txt', 'r') 25 | 26 | You can now read the content: 27 | 28 | .. code:: python 29 | 30 | In [2]: print(f.read()) 31 | ! 32 | service timestamps debug datetime msec localtime show-timezone year 33 | service timestamps log datetime msec localtime show-timezone year 34 | service password-encryption 35 | service sequence-numbers 36 | ! 37 | no ip domain lookup 38 | ! 39 | ip ssh version 2 40 | ! 41 | The **file** object has a special ``closed`` attribute that lets you check whether a file is closed or not. If file is open, it returns ``False``: 42 | 43 | .. code:: python 44 | 45 | In [3]: f.closed 46 | Out[3]: False 47 | 48 | Now close file and check ``closed`` again: 49 | 50 | .. code:: python 51 | 52 | In [4]: f.close() 53 | 54 | In [5]: f.closed 55 | Out[5]: True 56 | 57 | If you try to read file an exception will be raised: 58 | 59 | .. code:: python 60 | 61 | In [6]: print(f.read()) 62 | ------------------------------------------------------------------ 63 | ValueError Traceback (most recent call last) 64 | in () 65 | ----> 1 print(f.read()) 66 | 67 | ValueError: I/O operation on closed file 68 | 69 | -------------------------------------------------------------------------------- /docs/source/book/13_iterator_generator/generator.rst: -------------------------------------------------------------------------------- 1 | Generator 2 | --------------------- 3 | 4 | Generators are a special class of functions that allows you to easily create 5 | your own iterators. Unlike regular functions, a generator doesn't just 6 | return a value and exit, but returns an iterator that returns the elements one at a time. 7 | 8 | .. note:: 9 | 10 | Generators are not covered in this book and are only mentioned here because 11 | they are a fairly straightforward way to create iterators. 12 | `More about generators `__ 13 | 14 | A normal function exits if: 15 | 16 | * execution reached the ``return`` statement 17 | * function code is ended (this works as ``return None`` expression) 18 | * an exception raised 19 | 20 | After function execution is finished the control is returned and program 21 | execution goes further. All arguments that were passed to function like 22 | local variables, all of this is lost. Only the result that returned 23 | a function remains. 24 | 25 | A function can return a list of elements, multiple objects or different results 26 | depending on arguments, but it always returns a single result. 27 | 28 | Generator generates values. Values are then returned on demand and after return 29 | of one value a function-generator is suspended until the next value is 30 | requested. Between requests, generator retains its state. 31 | 32 | Python allows generators to be created in two ways: 33 | 34 | * generator expression 35 | * generator function 36 | 37 | 38 | generator expression 39 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 40 | 41 | Generator expression uses the same syntax as a list comprehensions, but returns 42 | iterator, not list (notе the parentheses instead of the square brackets): 43 | 44 | .. code:: python 45 | 46 | In [1]: genexpr = (x**2 for x in range(10000)) 47 | 48 | In [2]: genexpr 49 | Out[2]: at 0xb571ec8c> 50 | 51 | In [3]: next(genexpr) 52 | Out[3]: 0 53 | 54 | In [4]: next(genexpr) 55 | Out[4]: 1 56 | 57 | In [5]: next(genexpr) 58 | Out[5]: 4 59 | 60 | 61 | It is useful when working with a large iterable object or infinite iterator. 62 | 63 | -------------------------------------------------------------------------------- /docs/source/book/20_jinja2/assignments.rst: -------------------------------------------------------------------------------- 1 | set 2 | --- 3 | 4 | You can assign values to variables inside template. These can be new variables 5 | or there may be modified values of variables that have been passed to template. 6 | In this way you can remember a value that for example was obtained by using 7 | several filters. Then use variable name instead of repeating all filters. 8 | 9 | Template example templates/set.txt in which ``set`` expression is used to 10 | specify shorter parameter names: 11 | 12 | :: 13 | 14 | {% for intf, params in trunks | dictsort %} 15 | {% set vlans = params.vlans %} 16 | {% set action = params.action %} 17 | 18 | interface {{ intf }} 19 | {% if vlans is iterable %} 20 | {% if action == 'add' %} 21 | switchport trunk allowed vlan add {{ vlans | join(',') }} 22 | {% elif action == 'delete' %} 23 | switchport trunk allowed vlan remove {{ vlans | join(',') }} 24 | {% else %} 25 | switchport trunk allowed vlan {{ vlans | join(',') }} 26 | {% endif %} 27 | {% else %} 28 | {% if action == 'add' %} 29 | switchport trunk allowed vlan add {{ vlans }} 30 | {% elif action == 'delete' %} 31 | switchport trunk allowed vlan remove {{ vlans }} 32 | {% else %} 33 | switchport trunk allowed vlan {{ vlans }} 34 | {% endif %} 35 | {% endif %} 36 | {% endfor %} 37 | 38 | Note the second and third lines: 39 | 40 | :: 41 | 42 | {% set vlans = params.vlans %} 43 | {% set action = params.action %} 44 | 45 | In this way new variables are created and these new values are used. It makes 46 | template look clearer. 47 | 48 | Data file (data_files/set.yml): 49 | 50 | .. code:: json 51 | 52 | trunks: 53 | Fa0/1: 54 | action: add 55 | vlans: 56 | - 10 57 | - 20 58 | Fa0/2: 59 | action: only 60 | vlans: 61 | - 10 62 | - 30 63 | Fa0/3: 64 | action: delete 65 | vlans: 10 66 | 67 | The result of execution: 68 | 69 | :: 70 | 71 | $ python cfg_gen.py templates/set.txt data_files/set.yml 72 | 73 | interface Fa0/1 74 | switchport trunk allowed vlan add 10,20 75 | 76 | interface Fa0/2 77 | switchport trunk allowed vlan 10,30 78 | 79 | interface Fa0/3 80 | switchport trunk allowed vlan remove 10 81 | 82 | -------------------------------------------------------------------------------- /docs/source/book/15_module_re/sub.rst: -------------------------------------------------------------------------------- 1 | Function re.sub 2 | -------------- 3 | 4 | Function ``re.sub`` works similary to ``replace`` method in strings. But in 5 | ``re.sub`` you can use regex and therefore make substitutions using more complex conditions. 6 | Replace commas, square brackets and via word with space in ospf_route string: 7 | 8 | .. code:: python 9 | 10 | In [7]: ospf_route = 'O 10.0.24.0/24 [110/41] via 10.0.13.3, 3d18h, FastEthernet0/0' 11 | 12 | In [8]: re.sub(r'(via|[,\[\]])', ' ', ospf_route) 13 | Out[8]: 'O 10.0.24.0/24 110/41 10.0.13.3 3d18h FastEthernet0/0' 14 | 15 | With ``re.sub`` you can transform a string. For example, convert mac_table string to: 16 | 17 | .. code:: python 18 | 19 | In [9]: mac_table = ''' 20 | ...: 100 aabb.cc10.7000 DYNAMIC Gi0/1 21 | ...: 200 aabb.cc20.7000 DYNAMIC Gi0/2 22 | ...: 300 aabb.cc30.7000 DYNAMIC Gi0/3 23 | ...: 100 aabb.cc40.7000 DYNAMIC Gi0/4 24 | ...: 500 aabb.cc50.7000 DYNAMIC Gi0/5 25 | ...: 200 aabb.cc60.7000 DYNAMIC Gi0/6 26 | ...: 300 aabb.cc70.7000 DYNAMIC Gi0/7 27 | ...: ''' 28 | 29 | In [4]: print(re.sub(r' *(\d+) +' 30 | ...: r'([a-f0-9]+)\.' 31 | ...: r'([a-f0-9]+)\.' 32 | ...: r'([a-f0-9]+) +\w+ +' 33 | ...: r'(\S+)', 34 | ...: r'\1 \2:\3:\4 \5', 35 | ...: mac_table)) 36 | ...: 37 | 38 | 100 aabb:cc10:7000 Gi0/1 39 | 200 aabb:cc20:7000 Gi0/2 40 | 300 aabb:cc30:7000 Gi0/3 41 | 100 aabb:cc40:7000 Gi0/4 42 | 500 aabb:cc50:7000 Gi0/5 43 | 200 aabb:cc60:7000 Gi0/6 44 | 300 aabb:cc70:7000 Gi0/7 45 | 46 | Regex is divided into groups: 47 | 48 | - ``(\d+)`` - the first group. VLAN number gets here 49 | - ``([a-f0-9]+).([a-f0-9]+).([a-f0-9]+)`` - the following three groups (2, 3, 4) describe MAC address 50 | - ``(\S+)`` - the fifth group. Describes an interface. 51 | 52 | In a second regex these groups are used. To refer to a group a backslash and a 53 | group number are used. To avoid backslash screening, raw string is used. 54 | As a result, the corresponding substrings will be substituted instead of group 55 | numbers. For example, format of MAC address record was also changed. 56 | -------------------------------------------------------------------------------- /docs/source/book/20_jinja2/template_syntax.rst: -------------------------------------------------------------------------------- 1 | Jinja2 template syntax 2 | ------------------------- 3 | 4 | So far, only variable substitution has been used in Jinja2 template examples. 5 | This is the simplest and most understandable example of using templates. 6 | Syntax of Jinja templates is not limited to this. 7 | 8 | In Jinja2 templates you can use : 9 | 10 | * variables 11 | * conditions (if/else) 12 | * loops (for) 13 | * filters - special built-in methods that allow to convert variables 14 | * tests - are used to check whether a variable matches a condition 15 | 16 | In addition, Jinja supports inheritance between templates and also allows 17 | adding the contents of one template to another. 18 | This section covers only few possibilities. More information about Jinja2 19 | templates can be found in `documentation `__. 20 | 21 | .. note:: 22 | 23 | All files used as examples in this subsection are in 3_template_syntax/ directory 24 | 25 | Script cfg_gen.py will be used to generate templates. 26 | 27 | .. code:: python 28 | 29 | from jinja2 import Environment, FileSystemLoader 30 | import yaml 31 | import sys 32 | import os 33 | 34 | # python cfg_gen.py templates/for.txt data_files/for.yml 35 | template_dir, template = os.path.split(sys.argv[1]) 36 | 37 | vars_file = sys.argv[2] 38 | 39 | env = Environment( 40 | loader=FileSystemLoader(template_dir), 41 | trim_blocks=True, 42 | lstrip_blocks=True) 43 | template = env.get_template(template_file) 44 | 45 | with open(vars_file) as f: 46 | vars_dict = yaml.safe_load(f) 47 | 48 | print(template.render(vars_dict)) 49 | 50 | In order to see the result, you have to call the script and give it two arguments: 51 | 52 | * template 53 | * file with variables in YAML format 54 | 55 | The result will be displayed on standard output stream. 56 | 57 | Example of script run: 58 | 59 | :: 60 | 61 | $ python cfg_gen.py templates/variables.txt data_files/vars.yml 62 | 63 | Parameters trim_blocks and lstrip_blocks are described in the following subsection. 64 | 65 | .. toctree:: 66 | :maxdepth: 1 67 | :hidden: 68 | 69 | whitespace_control 70 | syntax_variables 71 | syntax_for 72 | syntax_if 73 | syntax_filter 74 | syntax_test 75 | assignments 76 | include 77 | -------------------------------------------------------------------------------- /docs/source/book/10_useful_functions/filter.rst: -------------------------------------------------------------------------------- 1 | filter 2 | -------------- 3 | 4 | Function ``filter()`` applies function to all sequence elements and returns 5 | an iterator with those objects for which function has returned True. 6 | 7 | For example, return only those strings that contain numbers: 8 | 9 | .. code:: python 10 | 11 | In [1]: list_of_strings = ['one', 'two', 'list', '', 'dict', '100', '1', '50'] 12 | 13 | In [2]: filter(str.isdigit, list_of_strings) 14 | Out[2]: 15 | 16 | In [3]: list(filter(str.isdigit, list_of_strings)) 17 | Out[3]: ['100', '1', '50'] 18 | 19 | From the list of numbers leave only odd: 20 | 21 | .. code:: python 22 | 23 | In [3]: list(filter(lambda x: x % 2, [10, 111, 102, 213, 314, 515])) 24 | Out[3]: [111, 213, 515] 25 | 26 | Similarly, only even ones: 27 | 28 | .. code:: python 29 | 30 | In [4]: list(filter(lambda x: not x % 2, [10, 111, 102, 213, 314, 515])) 31 | Out[4]: [10, 102, 314] 32 | 33 | From the list of words leave only those with more than two letters: 34 | 35 | .. code:: python 36 | 37 | In [5]: list_of_words = ['one', 'two', 'list', '', 'dict'] 38 | 39 | In [6]: list(filter(lambda x: len(x) > 2, list_of_words)) 40 | Out[6]: ['one', 'two', 'list', 'dict'] 41 | 42 | List comprehension instead of filter 43 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 44 | 45 | As a rule, you can use list comprehension instead of ``filter``. 46 | 47 | Examples similar to those above in list comprehension version. 48 | 49 | Return only those strings that contain numbers: 50 | 51 | .. code:: python 52 | 53 | In [7]: list_of_strings = ['one', 'two', 'list', '', 'dict', '100', '1', '50'] 54 | 55 | In [8]: [s for s in list_of_strings if s.isdigit()] 56 | Out[8]: ['100', '1', '50'] 57 | 58 | Odd/even numbers: 59 | 60 | .. code:: python 61 | 62 | In [9]: nums = [10, 111, 102, 213, 314, 515] 63 | 64 | In [10]: [n for n in nums if n % 2] 65 | Out[10]: [111, 213, 515] 66 | 67 | In [11]: [n for n in nums if not n % 2] 68 | Out[11]: [10, 102, 314] 69 | 70 | From the list of words leave only those with more than two letters: 71 | 72 | .. code:: python 73 | 74 | In [12]: list_of_words = ['one', 'two', 'list', '', 'dict'] 75 | 76 | In [13]: [word for word in list_of_words if len(word) > 2] 77 | Out[13]: ['one', 'two', 'list', 'dict'] 78 | 79 | -------------------------------------------------------------------------------- /docs/source/book/09_functions/namespace.rst: -------------------------------------------------------------------------------- 1 | Namespace. Scope of variables 2 | ------------------------------------ 3 | 4 | Variables in Python have a scope. Depending on location in code where 5 | variable has been defined, scope is also defined, it determines where variable will be available. 6 | 7 | When using variable names in a program, Python searches, creates or changes 8 | these names in the corresponding namespace each time. Namespace that is available at each moment depends on area in which code is located. 9 | 10 | Python has a LEGB rule that it uses for variables search. 11 | For example, when accessing a variable within a function, Python searches for a variable in this order in scopes (before the first match): 12 | 13 | * L (local) - in local (within function) 14 | * E (enclosing) - in local area of outer functions (these are functions within which our function is located) 15 | * G (global) - in global (in script) 16 | * B (built-in) - in built-in (reserved Python values) 17 | 18 | Accordingly, there are local and global variables: 19 | 20 | * local variables: 21 | 22 | * variables that are defined within function 23 | * these variables become unavailable after exit from function 24 | 25 | * global variables: 26 | 27 | * variables that are defined outside the function 28 | * these variables are 'global' only within a module 29 | * for example, to be available in another module they must be imported 30 | 31 | Example of local intf_config: 32 | 33 | .. code:: python 34 | 35 | In [1]: def configure_intf(intf_name, ip, mask): 36 | ...: intf_config = f'interface {intf_name}\nip address {ip} {mask}' 37 | ...: return intf_config 38 | ...: 39 | 40 | In [2]: intf_config 41 | --------------------------------------------------------------------------- 42 | NameError Traceback (most recent call last) 43 | in 44 | ----> 1 intf_config 45 | 46 | NameError: name 'intf_config' is not defined 47 | 48 | 49 | Note that intf_config variable is not available outside of function. To get the 50 | result of a function you must call a function and assign result to a variable: 51 | 52 | .. code:: python 53 | 54 | In [3]: result = configure_intf('F0/0', '10.1.1.1', '255.255.255.0') 55 | 56 | In [4]: result 57 | Out[4]: 'interface F0/0\nip address 10.1.1.1 255.255.255.0' 58 | 59 | 60 | -------------------------------------------------------------------------------- /docs/source/book/06_control_structures/for_if.rst: -------------------------------------------------------------------------------- 1 | Combination for and if 2 | ~~~~~~~~~~~~~~~~~~~ 3 | 4 | Consider example of combining ``for`` and ``if``. 5 | 6 | Generate_access_port_config.py file: 7 | 8 | .. code-block:: python 9 | :linenos: 10 | 11 | access_template = ['switchport mode access', 12 | 'switchport access vlan', 13 | 'spanning-tree portfast', 14 | 'spanning-tree bpduguard enable'] 15 | 16 | access = {'0/12': 10, '0/14': 11, '0/16': 17, '0/17': 150} 17 | 18 | for intf, vlan in fast_int['access'].items(): 19 | print('interface FastEthernet' + intf) 20 | for command in access_template: 21 | if command.endswith('access vlan'): 22 | print(' {} {}'.format(command, vlan)) 23 | else: 24 | print(' {}'.format(command)) 25 | 26 | Comments to the code: 27 | 28 | * The first ``for`` loop iterates keys and values in nested fast\_int['access'] dictionary 29 | * At this moment of loop the current key is stored in *intf* variable 30 | * At this moment of loop the current value is stored in *vlan* variable 31 | * String “interface Fastethernet” is displayed with interface number added 32 | * The second loop ``for`` iterates commands from *access_template* list 33 | * Since *switchport access to vlan* command requires a VLAN number: 34 | 35 | * within second loop ``for`` commands are checked 36 | * if command ends with “access vlan” 37 | 38 | * command is displayed and VLAN number is added to it 39 | 40 | * in all other cases, command is simply displayed 41 | 42 | 43 | Result of script execution: 44 | 45 | :: 46 | 47 | $ python generate_access_port_config.py 48 | interface FastEthernet0/12 49 | switchport mode access 50 | switchport access vlan 10 51 | spanning-tree portfast 52 | spanning-tree bpduguard enable 53 | interface FastEthernet0/14 54 | switchport mode access 55 | switchport access vlan 11 56 | spanning-tree portfast 57 | spanning-tree bpduguard enable 58 | interface FastEthernet0/16 59 | switchport mode access 60 | switchport access vlan 17 61 | spanning-tree portfast 62 | spanning-tree bpduguard enable 63 | interface FastEthernet0/17 64 | switchport mode access 65 | switchport access vlan 150 66 | spanning-tree portfast 67 | spanning-tree bpduguard enable 68 | 69 | -------------------------------------------------------------------------------- /docs/source/book/19_concurrent_connections/thread_count.rst: -------------------------------------------------------------------------------- 1 | Number of threads 2 | ------------------ 3 | 4 | How many threads you need to use when connecting to device? There is no clear 5 | answer to this question. The number of threads depends at least on which 6 | computer runs the script (OS, memory, processor), on network itself (delays). 7 | 8 | So instead of looking for the perfect number of threads, you have to measure 9 | the number on your computer, your network, your script. For example, in the 10 | examples to this section there is a script netmiko_count_threads.py that runs 11 | the same function with different threads and displays runtime information. 12 | Function by default uses a small number of devices from the devices_all.yaml 13 | file and a small number of threads, but it can be adapted to any number based 14 | on your network. 15 | 16 | Example of connecting to 5,000 devices with different number of threads: 17 | 18 | :: 19 | 20 | Number of devices: 5460 21 | 22 | #30 threads 23 | ---------------------------------------- 24 | Execution time: 0:09:17.187867 25 | 26 | #50 threads 27 | ---------------------------------------- 28 | Execution time: 0:09:17.604252 29 | 30 | #70 threads 31 | ---------------------------------------- 32 | Execution time: 0:09:17.117332 33 | 34 | #90 threads 35 | ---------------------------------------- 36 | Execution time: 0:09:16.693774 37 | 38 | #100 threads 39 | ---------------------------------------- 40 | Execution time: 0:09:17.083294 41 | 42 | #120 threads 43 | ---------------------------------------- 44 | Execution time: 0:09:17.945270 45 | 46 | #140 threads 47 | ---------------------------------------- 48 | Execution time: 0:09:18.114993 49 | 50 | #200 threads 51 | ---------------------------------------- 52 | Execution time: 0:11:12.951247 53 | 54 | #300 threads 55 | ---------------------------------------- 56 | Execution time: 0:14:03.790432 57 | 58 | In this case, the execution time with 30 threads and 120 threads is the same 59 | and after time only increases. This is because switching between threads also 60 | takes a lot of time and the more streams the more switching. And from some moment 61 | it makes no sense to increase number of threads. For this example 62 | (this PC, code and number of devices), the optimal number is approximately 50 threads. 63 | We're not taking 30 here in order to make a reserve. 64 | 65 | 66 | -------------------------------------------------------------------------------- /docs/source/book/01_intro/os_and_editor.rst: -------------------------------------------------------------------------------- 1 | OS and editor 2 | ============= 3 | 4 | You can choose any OS and any editor but it is better to use Python version 3.7 5 | because book uses this version. All examples in book were run on Debian, other 6 | operating systems may have a slightly different output. You can use Linux, 7 | macOS or Windows to perform tasks from a book. 8 | 9 | You can select any text editor or IDE that supports Python. Generally, working 10 | with Python requires minimal editor settings and often the editor recognizes 11 | Python by default. 12 | 13 | Thonny 14 | ^^^^^^^ 15 | 16 | `Thonny `__. 17 | 18 | Great editor for beginners: 19 | 20 | * supports Python 3.10 and can install both itself and Python 3.10 at once 21 | * work with different versions of Python and virtual environments is conveniently done, you can select the version very clearly and this is not hidden in the depths of the settings 22 | * multiple debugger options 23 | * the nicer debugger is simply indispensable for beginners to learn Python, it shows step by step how each expression is evaluated in Python 24 | * the faster debugger generally works like a standard debugger 25 | * there are all the standard goodies with autocomplete, highlights, and so on (some may need to be enabled in the settings) 26 | * conveniently highlights unclosed quotes/brackets 27 | * supports Windows, Mac, Linux 28 | * user-friendly interface and it is possible to add/remove sections of the interface at will 29 | 30 | 31 | Mu editor 32 | ^^^^^^^^^ 33 | 34 | `Mu editor `__ is a simple Python editor for beginner programmers. 35 | 36 | Mu has clean and simple user interface. It has important features such as 37 | checking code against PEP 8 and debugger. 38 | Plus, Mu runs on different operating systems (macOS, Windows, Linux). 39 | 40 | .. note:: 41 | `Mu tutorials `__ 42 | 43 | 44 | IDE PyCharm 45 | ^^^^^^^^^^^ 46 | 47 | `PyCharm `__ — is an integrated development 48 | environment for Python. For beginners it may be difficult 49 | option due to the large number of settings but it depends on personal 50 | preferences. Pycharm supports a huge number of features, even in free version. 51 | 52 | Pycharm is a great IDE but I think it's a little difficult for beginners. 53 | I wouldn't recommend using it if you're not familiar with it and you're just 54 | starting to learn Python. You can always switch to it after book but for now 55 | it's better to try something else. 56 | 57 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/convert_type.rst: -------------------------------------------------------------------------------- 1 | Types conversion 2 | -------------------- 3 | 4 | Python has several useful built-in features that allow data to be converted from one type to another. 5 | 6 | ``int`` 7 | ~~~~~~~~~ 8 | 9 | ``int`` converts a string to int: 10 | 11 | .. code:: python 12 | 13 | In [1]: int("10") 14 | Out[1]: 10 15 | 16 | Using ``int`` function you can convert a binary number into a decimal number (binary number must be written as a string) 17 | 18 | .. code:: python 19 | 20 | In [2]: int("11111111", 2) 21 | Out[2]: 255 22 | 23 | ``bin`` 24 | ~~~~~~~~~ 25 | 26 | You can convert a decimal number to binary format with ``bin``: 27 | 28 | .. code:: python 29 | 30 | In [3]: bin(10) 31 | Out[3]: '0b1010' 32 | 33 | In [4]: bin(255) 34 | Out[4]: '0b11111111' 35 | 36 | ``hex`` 37 | ~~~~~~~~~ 38 | 39 | A similar function exists for conversion to hexadecimal format: 40 | 41 | .. code:: python 42 | 43 | In [5]: hex(10) 44 | Out[5]: '0xa' 45 | 46 | In [6]: hex(255) 47 | Out[6]: '0xff' 48 | 49 | ``list`` 50 | ~~~~~~~~~~ 51 | 52 | Function ``list`` converts an argument to a list: 53 | 54 | .. code:: python 55 | 56 | In [7]: list("string") 57 | Out[7]: ['s', 't', 'r', 'i', 'n', 'g'] 58 | 59 | In [8]: list({1, 2, 3}) 60 | Out[8]: [1, 2, 3] 61 | 62 | In [9]: list((1, 2, 3, 4)) 63 | Out[9]: [1, 2, 3, 4] 64 | 65 | ``set`` 66 | ~~~~~~~~~ 67 | 68 | Function ``set`` converts an argument into a set: 69 | 70 | .. code:: python 71 | 72 | In [10]: set([1, 2, 3, 3, 4, 4, 4, 4]) 73 | Out[10]: {1, 2, 3, 4} 74 | 75 | In [11]: set((1, 2, 3, 3, 4, 4, 4, 4)) 76 | Out[11]: {1, 2, 3, 4} 77 | 78 | In [12]: set("string string") 79 | Out[12]: {' ', 'g', 'i', 'n', 'r', 's', 't'} 80 | 81 | This function is very useful when you need to get unique elements in a sequence. 82 | 83 | ``tuple`` 84 | ~~~~~~~~~~~ 85 | 86 | Function ``tuple`` converts argument into a tuple: 87 | 88 | .. code:: python 89 | 90 | In [13]: tuple([1, 2, 3, 4]) 91 | Out[13]: (1, 2, 3, 4) 92 | 93 | In [14]: tuple({1, 2, 3, 4}) 94 | Out[14]: (1, 2, 3, 4) 95 | 96 | In [15]: tuple("string") 97 | Out[15]: ('s', 't', 'r', 'i', 'n', 'g') 98 | 99 | This can be useful if you want an immutable object. 100 | 101 | ``str`` 102 | ~~~~~~~~~ 103 | 104 | Function ``str`` converts an argument into a string: 105 | 106 | .. code:: python 107 | 108 | In [16]: str(10) 109 | Out[16]: '10' 110 | -------------------------------------------------------------------------------- /docs/source/exercises/12_exercises.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | Tasks 6 | ======= 7 | 8 | .. include:: ./exercises_intro.rst 9 | 10 | Task 12.1 11 | ~~~~~~~~~~~~ 12 | 13 | Create a ping_ip_addresses function that checks if IP addresses are pingable. 14 | 15 | The function expects a list of IP addresses as an argument. 16 | 17 | The function must return a tuple with two lists: 18 | 19 | * list of available IP addresses 20 | * list of unavailable IP addresses 21 | 22 | To check the availability of an IP address, use the ping command. 23 | 24 | Restriction: All tasks must be done using the topics covered in this and previous chapters. 25 | 26 | Task 12.2 27 | ~~~~~~~~~~~~ 28 | 29 | The ping_ip_addresses function from task 12.1 only accepts a list of addresses, 30 | but it would be convenient to be able to specify addresses using a range, 31 | for example 192.168.100.1-10. 32 | 33 | In this task, you need to create a function convert_ranges_to_ip_list that 34 | converts a list of IP addresses in different formats into a list where each 35 | IP address is listed separately. 36 | 37 | The function expects as an argument a list containing IP addresses 38 | and/or ranges of IP addresses. 39 | 40 | List items can be in the format: 41 | 42 | * 10.1.1.1 43 | * 10.1.1.1-10.1.1.10 44 | * 10.1.1.1-10 45 | 46 | If the address is specified as a range, the range must be expanded into 47 | individual addresses, including the last address in the range. 48 | To simplify the task, we can assume that only the last octet of the 49 | address changes in the range. 50 | 51 | The function returns a list of IP addresses. 52 | 53 | For example, if you pass the following list to the convert_ranges_to_ip_list function: 54 | 55 | .. code:: python 56 | 57 | ['8.8.4.4', '1.1.1.1-3', '172.21.41.128-172.21.41.132'] 58 | 59 | The function should return a list like this: 60 | 61 | .. code:: python 62 | 63 | ['8.8.4.4', '1.1.1.1', '1.1.1.2', '1.1.1.3', '172.21.41.128', 64 | '172.21.41.129', '172.21.41.130', '172.21.41.131', '172.21.41.132'] 65 | 66 | 67 | Task 12.3 68 | ~~~~~~~~~~~~ 69 | 70 | Create a function print_ip_table that prints a table of available 71 | and unavailable IP addresses. 72 | 73 | The function expects two lists as arguments: 74 | 75 | * list of available IP addresses 76 | * list of unavailable IP addresses 77 | 78 | The result of the function is printing a table to the stdout: 79 | 80 | :: 81 | 82 | Reachable Unreachable 83 | ----------- ------------- 84 | 10.1.1.1 10.1.1.7 85 | 10.1.1.2 10.1.1.8 86 | 10.1.1.9 87 | -------------------------------------------------------------------------------- /docs/source/_templates/footer.html: -------------------------------------------------------------------------------- 1 |
2 | {% if (theme_prev_next_buttons_location == 'bottom' or theme_prev_next_buttons_location == 'both') and (next or prev) %} 3 | 11 | {% endif %} 12 | 13 |
14 | 15 |
16 |

17 | {%- if show_copyright %} 18 | {%- if hasdoc('copyright') %} 19 | {% set path = pathto('copyright') %} 20 | {% set copyright = copyright|e %} 21 | © {% trans %}Copyright{% endtrans %} {{ copyright }}. 22 | {%- else %} 23 | {% set copyright = copyright|e %} 24 | © {{ copyright }}. 25 | {%- endif %} 26 | {%- endif %} 27 | {%- if build_id and build_url %} 28 | 29 | {# Translators: Build is a noun, not a verb #} 30 | {% trans %}Build{% endtrans %} 31 | {{ build_id }}. 32 | 33 | {%- elif last_updated %} 34 | 35 | {% trans last_updated=last_updated|e %}Last updated on {{ last_updated }}.{% endtrans %} 36 | 37 | {%- endif %} 38 | Translated from Russian by Aidar Khairullin 39 |

40 |
41 | 42 | {%- if show_sphinx %} 43 | {% set sphinx_web = 'Sphinx' %} 44 | {% set readthedocs_web = 'Read the Docs' %} 45 | {% trans sphinx_web=sphinx_web, readthedocs_web=readthedocs_web %}Built with {{ sphinx_web }} using a{% endtrans %} {% trans %}theme{% endtrans %} {% trans %}provided by {{ readthedocs_web }}{% endtrans %}. 46 | {%- endif %} 47 | 48 |
49 |

50 | 51 | This work is licensed under a CC-BY-SA-4.0. 52 | 53 |

54 |
55 | 56 | {%- block extrafooter %} {% endblock %} 57 | 58 |
59 | 60 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/check_type.rst: -------------------------------------------------------------------------------- 1 | Types checking 2 | ~~~~~~~~~~~~~~ 3 | 4 | This type of error can occur when converting data types: 5 | 6 | .. code:: python 7 | 8 | In [1]: int('a') 9 | ------------------------------------------------------ 10 | ValueError Traceback (most recent call last) 11 | in () 12 | ----> 1 int('a') 13 | 14 | ValueError: invalid literal for int() with base 10: 'a' 15 | 16 | Error is perfectly logical. We're trying to convert string 'a' into decimal format. 17 | For example, this can be useful when you want to go through a list of strings and convert to a number the strings that contain numbers, you can get that error. 18 | To avoid error, it would be nice to be able to check what we're working with. 19 | 20 | ``isdigit`` 21 | ^^^^^^^^^^^^^ 22 | 23 | Python has such methods. For example, ``isdigit`` method can be used to check whether a string consists only of digits: 24 | 25 | .. code:: python 26 | 27 | In [2]: "a".isdigit() 28 | Out[2]: False 29 | 30 | In [3]: "a10".isdigit() 31 | Out[3]: False 32 | 33 | In [4]: "10".isdigit() 34 | Out[4]: True 35 | 36 | 37 | ``isalpha`` 38 | ^^^^^^^^^^^^^ 39 | 40 | Method ``isalpha`` makes it possible to check whether a string consists only of letters: 41 | 42 | .. code:: python 43 | 44 | In [7]: "a".isalpha() 45 | Out[7]: True 46 | 47 | In [8]: "a100".isalpha() 48 | Out[8]: False 49 | 50 | In [9]: "a-- ".isalpha() 51 | Out[9]: False 52 | 53 | In [10]: "a ".isalpha() 54 | Out[10]: False 55 | 56 | ``isalnum`` 57 | ^^^^^^^^^^^^^ 58 | 59 | Method ``isalnum`` makes it possible to check whether a string consists of letters or numbers: 60 | 61 | .. code:: python 62 | 63 | In [11]: "a".isalnum() 64 | Out[1]: True 65 | 66 | In [12]: "a10".isalnum() 67 | Out[12]: True 68 | 69 | ``type`` 70 | ^^^^^^^^^^ 71 | 72 | Sometimes, depending on the result, a library or function can return different types of objects. For example, if there is one object, string is returned. If several, tuple is returned. 73 | We have to construct the program in different ways, depending on whether a string or a tuple has been returned. 74 | 75 | Method ``type`` function can help: 76 | 77 | .. code:: python 78 | 79 | In [13]: type("string") 80 | Out[13]: str 81 | 82 | In [14]: type("string") == str 83 | Out[14]: True 84 | 85 | Similar to tuple (and other data types): 86 | 87 | .. code:: python 88 | 89 | In [15]: type((1, 2, 3)) 90 | Out[15]: tuple 91 | 92 | In [16]: type((1, 2, 3)) == tuple 93 | Out[16]: True 94 | 95 | In [17]: type((1, 2, 3)) == list 96 | Out[17]: False 97 | 98 | -------------------------------------------------------------------------------- /docs/source/book/09_functions/func_params_args.rst: -------------------------------------------------------------------------------- 1 | Function parameters and arguments 2 | ############################# 3 | 4 | The purpose of creating a function is typically to take a piece of code that performs a particular task to a separate object. This allows you to use this piece of code multiple times without having to re-create it in program. 5 | 6 | Typically, a function must perform some actions with input values and produce an output. 7 | 8 | When working with functions it is important to distinguish: 9 | 10 | - **parameters** - variables that are used when creating a function. 11 | - **arguments** - actual values (data) that are passed to function when called. 12 | 13 | For a function to receive incoming values, it must be created with parameters (func_check_passwd.py file): 14 | 15 | .. code:: python 16 | 17 | In [1]: def check_passwd(username, password): 18 | ...: if len(password) < 8: 19 | ...: print('Password is too short') 20 | ...: return False 21 | ...: elif username in password: 22 | ...: print('Password contains username') 23 | ...: return False 24 | ...: else: 25 | ...: print(f'Password for user {username} has passed all checks') 26 | ...: return True 27 | ...: 28 | 29 | In this case, function has two parameters: username and password. 30 | 31 | Function checks password and returns False if checks fail and True if password passed checks: 32 | 33 | .. code:: python 34 | 35 | In [2]: check_passwd('nata', '12345') 36 | Password is too short 37 | Out[2]: False 38 | 39 | In [3]: check_passwd('nata', '12345lsdkjflskfdjsnata') 40 | Password contains username 41 | Out[3]: False 42 | 43 | In [4]: check_passwd('nata', '12345lsdkjflskfdjs') 44 | Password for user nata has passed all checks 45 | Out[4]: True 46 | 47 | 48 | When defining a function in this way it is necessary to pass both arguments. If only one argument is passed, there is an error: 49 | 50 | .. code:: python 51 | 52 | In [5]: check_passwd('nata') 53 | --------------------------------------------------------------------------- 54 | TypeError Traceback (most recent call last) 55 | in 56 | ----> 1 check_passwd('nata') 57 | 58 | TypeError: check_passwd() missing 1 required positional argument: 'password' 59 | 60 | 61 | Similarly, an error will occur if three or more arguments are passed. 62 | 63 | .. toctree:: 64 | :maxdepth: 1 65 | :hidden: 66 | 67 | func_params_types.rst 68 | func_args_types.rst 69 | func_args_var.rst 70 | func_unpacking_args.rst 71 | 72 | -------------------------------------------------------------------------------- /docs/source/book/15_module_re/match.rst: -------------------------------------------------------------------------------- 1 | Match function 2 | ------------- 3 | 4 | Function ``match``: 5 | 6 | * is used to search at the beginning of string that corresponds to regex 7 | * returns Match object if match is found 8 | * returns ``None`` if no match was found 9 | 10 | ``Match`` function differs from ``search`` in that ``match`` always looks for a 11 | match at the beginning of the line. For example, if you repeat the example that 12 | was used for ``search`` function, but with ``match``: 13 | 14 | .. code:: python 15 | 16 | In [2]: import re 17 | 18 | In [3]: log = '%SW_MATM-4-MACFLAP_NOTIF: Host 01e2.4c18.0156 in vlan 10 is flapping between port Gi0/16 and port Gi0/24' 19 | 20 | In [4]: match = re.match(r'Host \S+ ' 21 | ...: r'in vlan (\d+) ' 22 | ...: r'is flapping between port ' 23 | ...: r'(\S+) and port (\S+)', log) 24 | ...: 25 | 26 | The result will be None: 27 | 28 | .. code:: python 29 | 30 | In [6]: print(match) 31 | None 32 | 33 | This is because ``match`` searches for Host word at the beginning of the line. But this message is in the middle. 34 | 35 | In this case it is easy to fix expression so that match() function finds match: 36 | 37 | .. code:: python 38 | 39 | In [4]: match = re.match(r'\S+: Host \S+ ' 40 | ...: r'in vlan (\d+) ' 41 | ...: r'is flapping between port ' 42 | ...: r'(\S+) and port (\S+)', log) 43 | ...: 44 | 45 | Expression ``\S+:`` was added before *Host* word. Now match will be found: 46 | 47 | .. code:: python 48 | 49 | In [11]: print(match) 50 | <_sre.SRE_Match object; span=(0, 104), match='%SW_MATM-4-MACFLAP_NOTIF: Host 01e2.4c18.0156 in > 51 | 52 | In [12]: match.groups() 53 | Out[12]: ('10', 'Gi0/16', 'Gi0/24') 54 | 55 | Example is similar to one used in ``search`` function with minor changes 56 | (parse_log_match match.py file): 57 | 58 | .. code:: python 59 | 60 | import re 61 | 62 | regex = (r'\S+: Host \S+ ' 63 | r'in vlan (\d+) ' 64 | r'is flapping between port ' 65 | r'(\S+) and port (\S+)') 66 | 67 | ports = set() 68 | 69 | with open('log.txt') as f: 70 | for line in f: 71 | match = re.match(regex, line) 72 | if match: 73 | vlan = match.group(1) 74 | ports.add(match.group(2)) 75 | ports.add(match.group(3)) 76 | 77 | print('Loop between ports {} in VLAN {}'.format(', '.join(ports), vlan)) 78 | 79 | The result is: 80 | 81 | :: 82 | 83 | $ python parse_log_match.py 84 | Loop between ports Gi0/19, Gi0/24, Gi0/16 in VLAN 10 85 | 86 | -------------------------------------------------------------------------------- /docs/source/book/22_oop_basics/init_method.rst: -------------------------------------------------------------------------------- 1 | Method ``__init__`` 2 | ~~~~~~~~~~~~~~~~~~ 3 | 4 | For ``info`` method to work correctly the instance should have ``hostname`` and 5 | ``model`` variables. If these variables are not available, an error will occur: 6 | 7 | .. code:: python 8 | 9 | In [15]: class Switch: 10 | ...: def info(self): 11 | ...: print(f'Hostname: {self.hostname}\nModel: {self.model}') 12 | ...: 13 | 14 | In [59]: sw2 = Switch() 15 | 16 | In [60]: sw2.info() 17 | --------------------------------------------------------------------------- 18 | AttributeError Traceback (most recent call last) 19 | in () 20 | ----> 1 sw2.info() 21 | 22 | in info(self) 23 | 1 class Switch: 24 | 2 def info(self): 25 | ----> 3 print(f'Hostname: {self.hostname}\nModel: {self.model}') 26 | 27 | AttributeError: 'Switch' object has no attribute 'hostname' 28 | 29 | Almost always, when an object is created it has some initial data. For example, 30 | to create a connection to device with netmiko you have to pass 31 | connection parameters. 32 | 33 | In Python these initial object data are specified in ``__init__``. 34 | Method ``__init__`` is executed after Python has created a new instance 35 | and ``__init__`` method is passed arguments with which instance was created: 36 | 37 | .. code:: python 38 | 39 | In [32]: class Switch: 40 | ...: def __init__(self, hostname, model): 41 | ...: self.hostname = hostname 42 | ...: self.model = model 43 | ...: 44 | ...: def info(self): 45 | ...: print(f'Hostname: {self.hostname}\nModel: {self.model}') 46 | ...: 47 | 48 | Note that each instance created from this class will have variables: 49 | ``self.model`` and ``self.hostname``. 50 | 51 | Now, when creating an instance of Switch class you have to specify 52 | ``hostname`` and ``model``: 53 | 54 | .. code:: python 55 | 56 | In [33]: sw1 = Switch('sw1', 'Cisco 3850') 57 | 58 | Accordingly, ``info`` method works without error: 59 | 60 | .. code:: python 61 | 62 | In [36]: sw1.info() 63 | Hostname: sw1 64 | Model: Cisco 3850 65 | 66 | .. note:: 67 | 68 | ``__init__`` method is sometimes called a class constructor, although 69 | technically in Python ``__new__`` method is executed first and then 70 | ``__init__``. In most cases there is no necessety to create 71 | ``__new__`` method. 72 | 73 | An important feature of ``__init__`` method is that it should not return 74 | anything. Python will generate an exception if it tries to do this. 75 | 76 | -------------------------------------------------------------------------------- /docs/source/book/16_unicode/python_3_convert.rst: -------------------------------------------------------------------------------- 1 | Conversion between bytes and strings 2 | ------------------------------------ 3 | 4 | You can't avoid working with bytes. For example, when working with a network 5 | or a filesystem, most often the result is returned in bytes. 6 | Accordingly, you need to know how to convert bytes to string and vice versa. 7 | That's what the encoding is for. 8 | 9 | Encoding can be represented as an encryption key that specifies: 10 | 11 | * how to "encrypt" a string to bytes (str -> bytes). Encode method used (similar to encrypt) 12 | * how to "decrypt" bytes to string (bytes -> str). Decode method used (similar to decrypt) 13 | 14 | This analogy makes it clear that string-byte and byte-string transformations 15 | must use the same encoding. 16 | 17 | ``encode``, ``decode`` 18 | ~~~~~~~~~~~~~~~~~~~~~~ 19 | 20 | ``encode`` method is used to convert string to bytes: 21 | 22 | .. code:: python 23 | 24 | In [1]: hi = 'привет' 25 | 26 | In [2]: hi.encode('utf-8') 27 | Out[2]: b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' 28 | 29 | In [3]: hi_bytes = hi.encode('utf-8') 30 | 31 | ``decode`` method to get a string from bytes: 32 | 33 | .. code:: python 34 | 35 | In [4]: hi_bytes 36 | Out[4]: b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' 37 | 38 | In [5]: hi_bytes.decode('utf-8') 39 | Out[5]: 'привет' 40 | 41 | ``str.encode``, ``bytes.decode`` 42 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 43 | 44 | Method ``encode`` is also present in str class (as are other methods of 45 | working with strings): 46 | 47 | .. code:: python 48 | 49 | In [6]: hi 50 | Out[6]: 'привет' 51 | 52 | In [7]: str.encode(hi, encoding='utf-8') 53 | Out[7]: b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' 54 | 55 | And ``decode`` method is available in bytes class (like other methods): 56 | 57 | .. code:: python 58 | 59 | In [8]: hi_bytes 60 | Out[8]: b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' 61 | 62 | In [9]: bytes.decode(hi_bytes, encoding='utf-8') 63 | Out[9]: 'привет' 64 | 65 | In these methods, encoding can be used as a key argument (examples above) 66 | or as a positional argument: 67 | 68 | .. code:: python 69 | 70 | In [10]: hi_bytes 71 | Out[10]: b'\xd0\xbf\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82' 72 | 73 | In [11]: bytes.decode(hi_bytes, 'utf-8') 74 | Out[11]: 'привет' 75 | 76 | How to work with Unicode and bytes 77 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 78 | 79 | There is a rule called a "Unicode sandwich": 80 | 81 | * bytes that the program reads must be converted to Unicode (string) as early as possible 82 | * inside the program work with Unicode 83 | * Unicode must be converted to bytes as soon as possible before transmitting 84 | 85 | 86 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/create_dict.rst: -------------------------------------------------------------------------------- 1 | Dictionary creation options 2 | ------------------------- 3 | 4 | Literal 5 | ~~~~~~~ 6 | 7 | A dictionary can be created with help of a literal: 8 | 9 | .. code:: python 10 | 11 | In [1]: r1 = {'model': '4451', 'ios': '15.4'} 12 | 13 | dict 14 | ~~~~ 15 | 16 | Construction ``dict`` allows you to create a dictionary in several ways. 17 | 18 | If you use strings as keys you can use this option to create a dictionary: 19 | 20 | .. code:: python 21 | 22 | In [2]: r1 = dict(model='4451', ios='15.4') 23 | 24 | In [3]: r1 25 | Out[3]: {'model': '4451', 'ios': '15.4'} 26 | 27 | The second option of creating a dictionary with dict(): 28 | 29 | .. code:: python 30 | 31 | In [4]: r1 = dict([('model','4451'), ('ios','15.4')]) 32 | 33 | In [5]: r1 34 | Out[5]: {'model': '4451', 'ios': '15.4'} 35 | 36 | dict.fromkeys 37 | ~~~~~~~~~~~~~ 38 | 39 | In a situation where you need to create a dictionary with known keys but so far 40 | empty values (or identical values), ``fromkeys`` method is very convenient: 41 | 42 | .. code:: python 43 | 44 | In [5]: d_keys = ['hostname', 'location', 'vendor', 'model', 'ios', 'ip'] 45 | 46 | In [6]: r1 = dict.fromkeys(d_keys) 47 | 48 | In [7]: r1 49 | Out[7]: 50 | {'hostname': None, 51 | 'location': None, 52 | 'vendor': None, 53 | 'model': None, 54 | 'ios': None, 55 | 'ip': None} 56 | 57 | 58 | By default ``fromkeys`` sets ``None`` value. But you can also pass your own value: 59 | 60 | .. code:: python 61 | 62 | In [8]: router_models = ['ISR2811', 'ISR2911', 'ISR2921', 'ASR9002'] 63 | 64 | In [9]: models_count = dict.fromkeys(router_models, 0) 65 | 66 | In [10]: models_count 67 | Out[10]: {'ISR2811': 0, 'ISR2911': 0, 'ISR2921': 0, 'ASR9002': 0} 68 | 69 | 70 | This option of creating a dictionary is not suitable for all cases. For example, 71 | if you use a mutable data type in value, a reference to the same object will be created: 72 | 73 | .. code:: python 74 | 75 | In [10]: router_models = ['ISR2811', 'ISR2911', 'ISR2921', 'ASR9002'] 76 | 77 | In [11]: routers = dict.fromkeys(router_models, []) 78 | ...: 79 | 80 | In [12]: routers 81 | Out[12]: {'ISR2811': [], 'ISR2911': [], 'ISR2921': [], 'ASR9002': []} 82 | 83 | In [13]: routers['ASR9002'].append('london_r1') 84 | 85 | In [14]: routers 86 | Out[14]: 87 | {'ISR2811': ['london_r1'], 88 | 'ISR2911': ['london_r1'], 89 | 'ISR2921': ['london_r1'], 90 | 'ASR9002': ['london_r1']} 91 | 92 | In this case, each key refers to the same list. Therefore, 93 | when a value is added to one of lists, others are updated. 94 | 95 | .. note:: 96 | A dictionary comprehension is better for this task. See section :ref:`x_comprehensions` 97 | -------------------------------------------------------------------------------- /docs/source/ToDo.rst: -------------------------------------------------------------------------------- 1 | ToDo 2 | ---- 3 | 4 | Упражнения 5 | ~~~~~~~~~~ 6 | 7 | +------------------+----------+------------------------------------+ 8 | | Кол-во заданий | Раздел | Название раздела | 9 | +==================+==========+====================================+ 10 | | 1 | 1 | Подготовка к работе | 11 | +------------------+----------+------------------------------------+ 12 | | 0 | 2 | Начало работы с Python | 13 | +------------------+----------+------------------------------------+ 14 | | 9 | 3 | Типы данных в Python | 15 | +------------------+----------+------------------------------------+ 16 | | 10 | 4 | Создание базовых скриптов | 17 | +------------------+----------+------------------------------------+ 18 | | 5 | 5 | Контроль хода программы | 19 | +------------------+----------+------------------------------------+ 20 | | 8 | 6 | Работа с файлами | 21 | +------------------+----------+------------------------------------+ 22 | | 9 | 7 | Функции | 23 | +------------------+----------+------------------------------------+ 24 | | 4 | 8 | Модули | 25 | +------------------+----------+------------------------------------+ 26 | | 10 | 9 | Регулярные выражения | 27 | +------------------+----------+------------------------------------+ 28 | | 6 | 10 | Сериализация данных | 29 | +------------------+----------+------------------------------------+ 30 | | 9 | 11 | Работа с базами данных | 31 | +------------------+----------+------------------------------------+ 32 | | 11 | 12 | Подключение к оборудованию | 33 | +------------------+----------+------------------------------------+ 34 | | 10 | 13 | Шаблоны конфигураций с Jinja | 35 | +------------------+----------+------------------------------------+ 36 | | 8 | 14 | TextFSM. Обработка вывода команд | 37 | +------------------+----------+------------------------------------+ 38 | | 12 | 15 | Ansible | 39 | +------------------+----------+------------------------------------+ 40 | 41 | Дополнительная информация 42 | ~~~~~~~~~~~~~~~~~~~~~~~~~ 43 | 44 | - IPython как управлящая консоль 45 | - [STRIKEOUT:запуск команд Linux из Python (subprocess)] 46 | - [STRIKEOUT:полезные модули (os, ipaddress)] 47 | - системы контроля версий 48 | - python package 49 | - OOP basics 50 | - iterator, generator 51 | - recursive function (basics) 52 | 53 | -------------------------------------------------------------------------------- /docs/source/about.rst: -------------------------------------------------------------------------------- 1 | About book 2 | ------- 3 | 4 | From the one hand, book is basic enough so everyone can handle it, 5 | from the other hand, book covers all 6 | main topics which allow you to develop skill independently in the future. 7 | Python deep dive is not a goal of this book. The goal is to explain Python 8 | basics in plain language and provide understanding of necessary tools for 9 | practical usage. Everything in this book is focused on network equipment and 10 | interaction with it. It right away gives opportunity to use knowledge gained 11 | at the course in network engineers daily work. All shown examples are based 12 | on Cisco equipment but, of course, they could be applied to any other equipment. 13 | 14 | Who is this book for? 15 | ~~~~~~~~~~~~~~~~~~ 16 | 17 | For network engineers with or without programming experience. All examples and 18 | homework will be formed with a focus on network equipment. This book will be 19 | useful for network engineers who want to automate their daily basis routine 20 | tasks and want start coding but don't know how to approach this. 21 | Still haven't decided whether it worth reading this book? Read :ref:`feedbacks `. 22 | 23 | 24 | OS and Python requirements 25 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 26 | 27 | All examples and terminal outputs in the book are shown on Debian Linux. 28 | Python 3.7 is used in this book but for the majority of examples Python 3.x 29 | will be enough. Only some examples requires Python version higher than 3.6. 30 | It always explicitly indicated and generally concerns some additional features. 31 | 32 | Examples 33 | ~~~~~~~ 34 | 35 | All examples from the book resides in 36 | `repository `__. 37 | All examples have educational purpose. It means they not necessarily show the 38 | best solution since they are based on information which was covered in previous 39 | chapters. Moreover, often enough the examples in chapters are developing in 40 | tasks. In other words, in tasks you have to create better, more universal and, 41 | in general, more proper version of code. It's better to write code from the book 42 | on your own or at least download examples and try to modify them. So the 43 | information will be better remembered. If you don't have this possibility, 44 | for example when you read book on road, it's better to repeat examples later 45 | on your own. In any case, it's necessary to do tasks manually. 46 | 47 | Tasks 48 | ~~~~~~~ 49 | 50 | All tasks and auxiliary files can be downloaded from the same 51 | `repository `__, 52 | where code examples are located. 53 | 54 | 55 | Book formats 56 | ~~~~~~~~~~~~ 57 | 58 | Book is available in PDF and Epub formats. Both of them are being updated 59 | automatically. 60 | 61 | -------------------------------------------------------------------------------- /docs/source/book/02_git_github/index.rst: -------------------------------------------------------------------------------- 1 | .. raw:: latex 2 | 3 | \newpage 4 | 5 | .. _git_github_index: 6 | 7 | 2. Using Git and Github 8 | ============================= 9 | 10 | .. warning:: 11 | 12 | This is a difficult section to understand. Especially because this section is at the very beginning of the book. 13 | You can skip it, but I would highly recommend trying to understand the basics of git/Github and use it to store tasks. 14 | 15 | 16 | There are a lot of tasks in book and you have to store them somewhere. One 17 | option is to use Git and Github to do this. Of course, there are other ways 18 | to do this but Github can be used for other things in future. 19 | Tasks and examples from book are in a separate `repository `__ 20 | on Github. They can be downloaded as a zip archive but it is better to work 21 | with repository using Git, then you can see changes made and easily update 22 | repository. If this is the first time working with Git and especially if this 23 | is the first version control system you work with, there are a lot of 24 | information, so this chapter focuses on practical side of question and it says: 25 | 26 | - How to start using Git and Github 27 | - How to perform basic setup 28 | - How to view information and/or changes 29 | 30 | There will be no much theory in this subsection but references to useful 31 | resources are listed. Try doing all basic settings for tasks and then continue 32 | reading the book. And at the end, when basic work with Git and Github is already 33 | routine, read more about them. What could Git be useful for: 34 | 35 | - to store configurations and all configuration changes 36 | - to store documentation and all its versions 37 | - to store schemes and all its versions 38 | - to store code and its versions 39 | 40 | Github allows you to centrally store all above items, but it should be taken 41 | into account that these resources will be available to others as well. Github 42 | also has private repositories, but even these probably should not contain 43 | information such as passwords. Of course, main use of Github is to place code 44 | of various projects. In addition, Github can be also used to: 45 | 46 | - host for your website (`GitHub 47 | Pages `__) 48 | - Hosting for online presentations and a tool to create them 49 | (`GitPitch `__) 50 | - together with `GitBook `__, it is also a platform for publishing books, documentation, etc 51 | 52 | 53 | .. toctree:: 54 | :maxdepth: 1 55 | :hidden: 56 | 57 | git_basics 58 | git_basics_bash_status 59 | git_basics_commands 60 | git_basics_additional 61 | git_github_auth 62 | git_github_changes 63 | pyneng_github 64 | further_reading 65 | ../../exercises/02_exercises.rst 66 | -------------------------------------------------------------------------------- /docs/source/book/06_control_structures/for_while_else.rst: -------------------------------------------------------------------------------- 1 | for/else, while/else 2 | -------------------- 3 | 4 | In loops ``for`` and ``while`` you may optionally use ``else`` block. 5 | 6 | for/else 7 | ~~~~~~~~ 8 | 9 | In loop ``for``: 10 | 11 | * block ``else`` is executed if loop has completed iteration of list 12 | * but it *does not execute* if ``break`` was applied in loop. 13 | 14 | Example of loop ``for`` with ``else`` (block ``else`` is executed after loop ``for``): 15 | 16 | .. code:: python 17 | 18 | In [1]: for num in range(5): 19 | ....: print(num) 20 | ....: else: 21 | ....: print("Run out of numbers") 22 | ....: 23 | 0 24 | 1 25 | 2 26 | 3 27 | 4 28 | Run out of numbers 29 | 30 | An example of loop ``for`` with ``else`` and ``break`` in loop (because of ``break``, block ``else`` is not applied): 31 | 32 | .. code:: python 33 | 34 | In [2]: for num in range(5): 35 | ....: if num == 3: 36 | ....: break 37 | ....: else: 38 | ....: print(num) 39 | ....: else: 40 | ....: print("Run out of numbers") 41 | ....: 42 | 0 43 | 1 44 | 2 45 | 46 | Example of loop ``for`` with ``else`` and ``continue`` in loop (``continue`` does not affect ``else`` block): 47 | 48 | .. code:: python 49 | 50 | In [3]: for num in range(5): 51 | ....: if num == 3: 52 | ....: continue 53 | ....: else: 54 | ....: print(num) 55 | ....: else: 56 | ....: print("Run out of numbers") 57 | ....: 58 | 0 59 | 1 60 | 2 61 | 4 62 | Run out of numbers 63 | 64 | while/else 65 | ~~~~~~~~~~ 66 | 67 | In loop ``while``: 68 | 69 | * block ``else`` is executed if loop has completed iteration of list 70 | * but it *does not execute* if ``break`` was applied in loop. 71 | 72 | Example of a loop ``while`` with ``else`` (block ``else`` runs after loop ``while``): 73 | 74 | .. code:: python 75 | 76 | In [4]: i = 0 77 | In [5]: while i < 5: 78 | ....: print(i) 79 | ....: i += 1 80 | ....: else: 81 | ....: print("The End") 82 | ....: 83 | 0 84 | 1 85 | 2 86 | 3 87 | 4 88 | The End 89 | 90 | An example of a loop ``while`` with ``else`` and ``break`` in loop (because of ``break``, block ``else`` is not applied): 91 | 92 | .. code:: python 93 | 94 | In [6]: i = 0 95 | 96 | In [7]: while i < 5: 97 | ....: if i == 3: 98 | ....: break 99 | ....: else: 100 | ....: print(i) 101 | ....: i += 1 102 | ....: else: 103 | ....: print("The End") 104 | ....: 105 | 0 106 | 1 107 | 2 108 | 109 | -------------------------------------------------------------------------------- /docs/source/book/19_concurrent_connections/concurrent_futures.rst: -------------------------------------------------------------------------------- 1 | Module concurrent.futures 2 | ------------------------- 3 | 4 | Module ``concurrent.futures`` provides a high-level interface for working with 5 | processes and threads. For both threads and processes the same interface 6 | is used which makes it easy to switch between them. 7 | 8 | If you compare this module with threading or multiprocessing, it has fewer 9 | features but with ``concurrent.futures`` it's easier to work and interface 10 | easier to understand. 11 | 12 | Concurrent.futures module allows to solve the problem of starting multiple 13 | threads/processes and getting data from them. For this purpose, module 14 | uses two classes: 15 | 16 | - ``ThreadPoolExecutor`` - for threads handling 17 | - ``ProcessPoolExecutor`` - for process handling 18 | 19 | Both classes use the same interface, so it is enough to deal with one and then 20 | just switch to other if necessary. 21 | 22 | Create an Executor object using ThreadPoolExecutor: 23 | 24 | .. code:: python 25 | 26 | executor = ThreadPoolExecutor(max_workers=5) 27 | 28 | After creating an Executor object, it has three methods: ``shutdown``, ``map``, 29 | and ``submit``. Method ``shutdown`` is responsible for the completion of 30 | threads/processes, ``map`` and ``submit`` methods are responsible for 31 | starting functions in different threads/processes. 32 | 33 | .. note:: 34 | 35 | In fact, map and submit can run not only functions but any callable object. 36 | However, only functions will be covered further. 37 | 38 | Method ``shutdown`` indicates that Executor object must be finished. However, 39 | if to ``shutdown`` method pass ``wait=True`` (default value), it will not 40 | return the result until all functions running in threads have been completed. 41 | If ``wait=False``, ``shutdown`` method returns instantly but script itself 42 | will not exit until all functions have been completed. 43 | 44 | Generally, ``shutdown`` is not explicitly used because when creating an 45 | Executor object in a context manager, ``shutdown`` is automatically called 46 | at the end of a block with ``wait=True``. 47 | 48 | .. code:: python 49 | 50 | with ThreadPoolExecutor(max_workers=5) as executor: 51 | ... 52 | 53 | Since map and submit methods start a function in threads or processes, code 54 | must at least have a function that performs one action and must be run in 55 | different threads with different arguments of the function. 56 | 57 | For example, if you need to ping multiple IP addresses in different threads you 58 | need to create a function that pings one IP address and then run this function 59 | in different threads for different IP addresses using concurrent.futures. 60 | 61 | 62 | .. toctree:: 63 | :maxdepth: 1 64 | :hidden: 65 | 66 | concurrent_futures_map 67 | concurrent_futures_submit 68 | concurrent_futures_processes 69 | -------------------------------------------------------------------------------- /docs/source/book/25_db/delete.rst: -------------------------------------------------------------------------------- 1 | DELETE 2 | ~~~~~~ 3 | 4 | DELETE operator is used to delete enties. It is commonly used together with WHERE operator. 5 | 6 | For example, *switch* table is: 7 | 8 | .. code:: sql 9 | 10 | new_db.db> SELECT * from switch; 11 | +----------------+----------+------------+-------------------+------------+-----------+ 12 | | mac | hostname | model | location | mngmt_ip | mngmt_vid | 13 | +----------------+----------+------------+-------------------+------------+-----------+ 14 | | 0010.D1DD.E1EE | sw1 | Cisco 3850 | London, Green Str | 10.255.1.1 | 255 | 15 | | 0020.A2AA.C2CC | sw2 | Cisco 3850 | London, Green Str | 10.255.1.2 | 255 | 16 | | 0040.A4AA.C2CC | sw4 | Cisco 3850 | London, Green Str | 10.255.1.4 | 255 | 17 | | 0050.A5AA.C3CC | sw5 | Cisco 3850 | London, Green Str | 10.255.1.5 | 255 | 18 | | 0060.A6AA.C4CC | sw6 | C3750 | London, Green Str | 10.255.1.6 | 255 | 19 | | 0070.A7AA.C5CC | sw7 | Cisco 3650 | London, Green Str | 10.255.1.7 | 255 | 20 | | 0030.A3AA.C1CC | sw3 | Cisco 3850 | London, Green Str | 10.255.1.3 | 255 | 21 | | 0080.A8AA.C8CC | sw8 | Cisco 3850 | London, Green Str | 10.255.1.8 | 255 | 22 | +----------------+----------+------------+-------------------+------------+-----------+ 23 | 8 rows in set 24 | Time: 0.033s 25 | 26 | Deleting information about sw8 switch is performed as follows: 27 | 28 | .. code:: sql 29 | 30 | new_db.db> DELETE from switch where hostname = 'sw8'; 31 | You're about to run a destructive command. 32 | Do you want to proceed? (y/n): y 33 | Your call! 34 | Query OK, 1 row affected 35 | Time: 0.008s 36 | 37 | No line with sw8 switch in the table now: 38 | 39 | .. code:: sql 40 | 41 | new_db.db> SELECT * from switch; 42 | +----------------+----------+------------+-------------------+------------+-----------+ 43 | | mac | hostname | model | location | mngmt_ip | mngmt_vid | 44 | +----------------+----------+------------+-------------------+------------+-----------+ 45 | | 0010.D1DD.E1EE | sw1 | Cisco 3850 | London, Green Str | 10.255.1.1 | 255 | 46 | | 0020.A2AA.C2CC | sw2 | Cisco 3850 | London, Green Str | 10.255.1.2 | 255 | 47 | | 0040.A4AA.C2CC | sw4 | Cisco 3850 | London, Green Str | 10.255.1.4 | 255 | 48 | | 0050.A5AA.C3CC | sw5 | Cisco 3850 | London, Green Str | 10.255.1.5 | 255 | 49 | | 0060.A6AA.C4CC | sw6 | C3750 | London, Green Str | 10.255.1.6 | 255 | 50 | | 0070.A7AA.C5CC | sw7 | Cisco 3650 | London, Green Str | 10.255.1.7 | 255 | 51 | | 0030.A3AA.C1CC | sw3 | Cisco 3850 | London, Green Str | 10.255.1.3 | 255 | 52 | +----------------+----------+------------+-------------------+------------+-----------+ 53 | 7 rows in set 54 | Time: 0.039s 55 | 56 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/numbers.rst: -------------------------------------------------------------------------------- 1 | Numbers 2 | ===== 3 | 4 | With numbers it is possible to perform various mathematical operations. 5 | 6 | .. code:: python 7 | 8 | In [1]: 1 + 2 9 | Out[1]: 3 10 | 11 | In [2]: 1.0 + 2 12 | Out[2]: 3.0 13 | 14 | In [3]: 10 - 4 15 | Out[3]: 6 16 | 17 | In [4]: 2**3 18 | Out[4]: 8 19 | 20 | Division int and float: 21 | 22 | .. code:: python 23 | 24 | In [5]: 10/3 25 | Out[5]: 3.3333333333333335 26 | 27 | In [6]: 10/3.0 28 | Out[6]: 3.3333333333333335 29 | 30 | The round() function - round a number to a given precision in decimal digits: 31 | 32 | .. code:: python 33 | 34 | In [9]: round(10/3.0, 2) 35 | Out[9]: 3.33 36 | 37 | In [10]: round(10/3.0, 4) 38 | Out[10]: 3.3333 39 | 40 | Remainder of division: 41 | 42 | .. code:: python 43 | 44 | In [11]: 10 % 3 45 | Out[11]: 1 46 | 47 | Comparison operators 48 | 49 | .. code:: python 50 | 51 | In [12]: 10 > 3.0 52 | Out[12]: True 53 | 54 | In [13]: 10 < 3 55 | Out[13]: False 56 | 57 | In [14]: 10 == 3 58 | Out[14]: False 59 | 60 | In [15]: 10 == 10 61 | Out[15]: True 62 | 63 | In [16]: 10 <= 10 64 | Out[16]: True 65 | 66 | In [17]: 10.0 == 10 67 | Out[17]: True 68 | 69 | The int() function allows converting to int type. The second argument can specify number system: 70 | 71 | .. code:: python 72 | 73 | In [18]: a = '11' 74 | 75 | In [19]: int(a) 76 | Out[19]: 11 77 | 78 | If you specify that string should be read as a binary number, the result is: 79 | 80 | .. code:: python 81 | 82 | In [20]: int(a, 2) 83 | Out[20]: 3 84 | 85 | Convert to int from float: 86 | 87 | .. code:: python 88 | 89 | In [21]: int(3.333) 90 | Out[21]: 3 91 | 92 | In [22]: int(3.9) 93 | Out[22]: 3 94 | 95 | The bin() function produces a binary representation of a number (note that the result is a string): 96 | 97 | .. code:: python 98 | 99 | In [23]: bin(8) 100 | Out[23]: '0b1000' 101 | 102 | In [24]: bin(255) 103 | Out[24]: '0b11111111' 104 | 105 | Similarly, function hex() produces a hexadecimal value: 106 | 107 | .. code:: python 108 | 109 | In [25]: hex(10) 110 | Out[25]: '0xa' 111 | 112 | And, of course, you can do several changes at the same time: 113 | 114 | .. code:: python 115 | 116 | In [26]: int('ff', 16) 117 | Out[26]: 255 118 | 119 | In [27]: bin(int('ff', 16)) 120 | Out[27]: '0b11111111' 121 | 122 | For more complex mathematical functions, Python has a ``math`` module: 123 | 124 | .. code:: python 125 | 126 | In [28]: import math 127 | 128 | In [29]: math.sqrt(9) 129 | Out[29]: 3.0 130 | 131 | In [30]: math.sqrt(10) 132 | Out[30]: 3.1622776601683795 133 | 134 | In [31]: math.factorial(3) 135 | Out[31]: 6 136 | 137 | In [32]: math.pi 138 | Out[32]: 3.141592653589793 139 | 140 | -------------------------------------------------------------------------------- /docs/source/book/10_useful_functions/map.rst: -------------------------------------------------------------------------------- 1 | map 2 | ----------- 3 | 4 | Function ``map`` applies function to each element of sequence and returns iterator with result. 5 | 6 | For example, ``map`` can be used to perform element transformations. Convert all strings to uppercase: 7 | 8 | .. code:: python 9 | 10 | In [1]: list_of_words = ['one', 'two', 'list', '', 'dict'] 11 | 12 | In [2]: map(str.upper, list_of_words) 13 | Out[2]: 14 | 15 | In [3]: list(map(str.upper, list_of_words)) 16 | Out[3]: ['ONE', 'TWO', 'LIST', '', 'DICT'] 17 | 18 | Converting to numbers: 19 | 20 | .. code:: python 21 | 22 | In [3]: list_of_str = ['1', '2', '5', '10'] 23 | 24 | In [4]: list(map(int, list_of_str)) 25 | Out[4]: [1, 2, 5, 10] 26 | 27 | With ``map`` it is convenient to use lambda expressions: 28 | 29 | .. code:: python 30 | 31 | In [5]: vlans = [100, 110, 150, 200, 201, 202] 32 | 33 | In [6]: list(map(lambda x: 'vlan {}'.format(x), vlans)) 34 | Out[6]: ['vlan 100', 'vlan 110', 'vlan 150', 'vlan 200', 'vlan 201', 'vlan 202'] 35 | 36 | If ``map`` function expects two arguments, two lists are passed: 37 | 38 | .. code:: python 39 | 40 | In [7]: nums = [1, 2, 3, 4, 5] 41 | 42 | In [8]: nums2 = [100, 200, 300, 400, 500] 43 | 44 | In [9]: list(map(lambda x, y: x*y, nums, nums2)) 45 | Out[9]: [100, 400, 900, 1600, 2500] 46 | 47 | List comprehension instead of map 48 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 49 | 50 | As a rule, you can use list comprehension instead of ``map``. 51 | The list comprehension option is often clearer, and in some cases even faster. 52 | 53 | `Alex Martelli response with comparison of map and list 54 | comprehension `__ 55 | 56 | But ``map`` can be more effective when you have to generate a large 57 | number of elements because ``map`` is an iterator and list comprehension generates a list. 58 | 59 | Examples similar to those above in list comprehension version. 60 | 61 | Convert all strings to uppercase: 62 | 63 | .. code:: python 64 | 65 | In [48]: list_of_words = ['one', 'two', 'list', '', 'dict'] 66 | 67 | In [49]: [str.upper(word) for word in list_of_words] 68 | Out[49]: ['ONE', 'TWO', 'LIST', '', 'DICT'] 69 | 70 | Converting to numbers: 71 | 72 | .. code:: python 73 | 74 | In [50]: list_of_str = ['1', '2', '5', '10'] 75 | 76 | In [51]: [int(i) for i in list_of_str] 77 | Out[51]: [1, 2, 5, 10] 78 | 79 | String formatting: 80 | 81 | .. code:: python 82 | 83 | In [52]: vlans = [100, 110, 150, 200, 201, 202] 84 | 85 | In [53]: ['vlan {}'.format(x) for x in vlans] 86 | Out[53]: ['vlan 100', 'vlan 110', 'vlan 150', 'vlan 200', 'vlan 201', 'vlan 202'] 87 | 88 | Use ``zip`` to get pairs of elements: 89 | 90 | .. code:: python 91 | 92 | In [54]: nums = [1, 2, 3, 4, 5] 93 | 94 | In [55]: nums2 = [100, 200, 300, 400, 500] 95 | 96 | In [56]: [x * y for x, y in zip(nums, nums2)] 97 | Out[56]: [100, 400, 900, 1600, 2500] 98 | 99 | -------------------------------------------------------------------------------- /docs/source/book/04_data_structures/lists.rst: -------------------------------------------------------------------------------- 1 | List 2 | ============= 3 | 4 | List in Python is: 5 | 6 | * sequence of elements separated by comma and enclosed in square brackets 7 | * mutable ordered data type 8 | 9 | Examples of lists: 10 | 11 | .. code:: python 12 | 13 | In [1]: list1 = [10,20,30,77] 14 | In [2]: list2 = ['one', 'dog', 'seven'] 15 | In [3]: list3 = [1, 20, 4.0, 'word'] 16 | 17 | Creating a list using a literal: 18 | 19 | .. code:: python 20 | 21 | In [1]: vlans = [10, 20, 30, 50] 22 | 23 | .. note:: 24 | 25 | Literal is an expression that creates an object. 26 | 27 | Create a list using ``list`` function: 28 | 29 | .. code:: python 30 | 31 | In [2]: list1 = list('router') 32 | 33 | In [3]: print(list1) 34 | ['r', 'o', 'u', 't', 'e', 'r'] 35 | 36 | Since a list is an ordered data type just like a string, in lists you can 37 | refer to an item by number, make slices: 38 | 39 | .. code:: python 40 | 41 | In [4]: list3 = [1, 20, 4.0, 'word'] 42 | 43 | In [5]: list3[1] 44 | Out[5]: 20 45 | 46 | In [6]: list3[1::] 47 | Out[6]: [20, 4.0, 'word'] 48 | 49 | In [7]: list3[-1] 50 | Out[7]: 'word' 51 | 52 | In [8]: list3[::-1] 53 | Out[8]: ['word', 4.0, 20, 1] 54 | 55 | You can reverse list by ``reverse`` method: 56 | 57 | .. code:: python 58 | 59 | In [10]: vlans = ['10', '15', '20', '30', '100-200'] 60 | 61 | In [11]: vlans.reverse() 62 | 63 | In [12]: vlans 64 | Out[12]: ['100-200', '30', '20', '15', '10'] 65 | 66 | Since lists are mutable, list elements can be changed: 67 | 68 | .. code:: python 69 | 70 | In [13]: list3 71 | Out[13]: [1, 20, 4.0, 'word'] 72 | 73 | In [14]: list3[0] = 'test' 74 | 75 | In [15]: list3 76 | Out[15]: ['test', 20, 4.0, 'word'] 77 | 78 | You can also create a list of lists. As in a regular list you can refer to 79 | items in nested lists: 80 | 81 | .. code:: python 82 | 83 | In [16]: interfaces = [['FastEthernet0/0', '15.0.15.1', 'YES', 'manual', 'up', 'up'], 84 | ....: ['FastEthernet0/1', '10.0.1.1', 'YES', 'manual', 'up', 'up'], 85 | ....: ['FastEthernet0/2', '10.0.2.1', 'YES', 'manual', 'up', 'down']] 86 | 87 | In [17]: interfaces[0][0] 88 | Out[17]: 'FastEthernet0/0' 89 | 90 | In [18]: interfaces[2][0] 91 | Out[18]: 'FastEthernet0/2' 92 | 93 | In [19]: interfaces[2][1] 94 | Out[19]: '10.0.2.1' 95 | 96 | The ``len`` function returns number of items in list: 97 | 98 | .. code:: python 99 | 100 | In [1]: items = [1, 2, 3] 101 | 102 | In [2]: len(items) 103 | Out[2]: 3 104 | 105 | And ``sorted`` function sorts list items in ascending order and returns 106 | a new list with sorted items: 107 | 108 | .. code:: python 109 | 110 | In [1]: names = ['John', 'Michael', 'Antony'] 111 | 112 | In [2]: sorted(names) 113 | Out[2]: ['Antony', 'John', 'Michael'] 114 | 115 | 116 | 117 | .. toctree:: 118 | :maxdepth: 1 119 | :hidden: 120 | 121 | list_methods 122 | --------------------------------------------------------------------------------