python for devops
RE Package
Character sets
The + after an item in a regular expression matches one or more of it. A number in brackets matches an exact number of characters.
1 | In [6]: print cc_list |
The . character has a special meaning. It is a wildcard and matches any character. To match against the actual . character, you must escape it using a backslash:
1 | >>> re.search(r'[A-Za-z]+@[a-z]+\.[a-z]+', cc_list) |
Character Classes
Python’s re offers character classes. These are pre-made characters sets. Some commonly used ones are \w, which is equivalent to [a-zA-Z0-9_] and \d which is equivalent to [0-9]. You can use the + modifier to match for multiple characters:
1 | >>> re.search(r'\w+', cc_list) |
Groups
1 | >>> matched = re.search(r'(\w+)\@(\w+)\.(\w+)', cc_list) |
Named Groups
You can also supply names for the groups by adding ?P
1 | >>> matched = re.search(r'(?P<name>\w+)\@(?P<SLD>\w+)\.(?P<TLD>\w+)', cc_list) |
Using IPython to run unix shell commands
1 | In [5]: ls = !ls -l /usr/bin |
Using ipython magic commands
1 | In [7]: %%bash |
The %%writefile is pretty tricky because you can write and test Python or Bash scripts on the fly, using IPython to execute them. Not a bad party trick at all:
1 | In [8]: %%writefile print_time.py |
Another very useful command, %who, will show you what is loaded into memory. It comes in quite handy when you have been working in a terminal that has been running for a long time:
1 | In [11]: %who |
Package Management
Descriptive Versioning
Most commonly in Python packages the following two variants: major.minor or major.minor.micro
- 0.0.1
- 1.0
- 2.1.1
A commonly accepted format for releases is: for major.minor.micro (used by the Semantic Versioning scheme
- major for backwards-incompatible changes
- minor adds features that are also backward-compatible
- micro adds backwards-compatible bug fxes
Assuming the current released version of the project under development is 1.0.0, it means the following outcomes are possible:
- If the release has backward-incompatible changes, the version is: 2.0.0
- Adding features that do not break compatibility: 1.1.0
- Fixing issues that also do not break compatibility: 1.0.1
The changelog
The below example is an actual portion of a changelog file in a production Python tool:
1 | 1.1.3 |
The example has four essential items that are providing information:
- The lastest version number released
- Is the latest release a backward-compatible one
- What was the release date of the last version
- Changes included in the release
Packaging solutions
A small Python project:
1 | hello-world |
Native Python packaging
Like the rest of the other packaging strategies, the project requires some files used by setuptools.
To continue, create a new virtual environment and then activate:
1 | $ python3 -m venv /tmp/packaging |
Setuptools is a requirement to produce a native Python package. It is a collection of tools and helpers to create and distribute Python packages.
Once the virtual environment is active, the following dependencies exist:
setuptools A set of utilities for packaging
twine A tool for registering and uploading packages
1 | $ pip install setuptools twine |
Package files
The file that describes the package to setuptools is named setup.py. It exists at the top level directory.
1 | cat setup.py |
The setup.py file will import two helpers from the setuptools module: setup, and find_packages. The setup function is what requires the rich description about the package, and the find_packages function is a utility to automatically detect where the Python files are, lastly, the classifiers describes certain aspects of the package like the license, operating systems supported, and Python versions. These classifiers are called trove classifiers and the Python Package Index has a detailed description of other classifiers available. Detailed descriptions make a package get discovered when uploaded to PyPI.
1 | hello-world tree |
To produce the source distribution from it, run the following command:
1 | hello-world python3 setup.py sdist |
The newly created tar.gz file is an installable package! This package can now be uploaded to the Python Package Index for others to install right from it. By following the version schema, it allows installers to ask for a specific version (0.0.1 in this case), and the extra metadata passed into the setup() function enables other tools to discover it and show information about it like the author, description, and version.
1 | hello-world pip install dist/hello-world-0.0.1.tar.gz |
The python package index
PyPI is a repository of Python software that allows users to host Python pakcages and also install from it.
1 | hello-world twine upload --repository-url https://test.pypi.org/legacy/ dist/hello-world-0.0.1.tar.gz |
deploy-pypi:
pandoc –from=markdown –to=rst README.md -o README.rst
python setup.py check –restructuredtext –strict –metadata
rm -rf dist
python setup.py sdist
twine upload dist/*
rm -f README.rst
1 | ### Hosting an internal package index |
(packaging) ➜ pypi tree
.
├── hello-world
│ └── hello-world-0.0.1.tar.gz
└── hello-world1
└── hello-world1-0.0.1.tar.gz
pypi pwd
/home/stan/Learning/python4devops/pypi
pypi python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) …
127.0.0.1 - - [01/Sep/2019 16:46:27] “GET /hello-world1/ HTTP/1.1” 200 -
127.0.0.1 - - [01/Sep/2019 16:46:27] “GET /hello-world1/hello-world1-0.0.1.tar.gz HTTP/1.1” 200 -
$ python3 -m venv /tmp/local-pypi
$ source /tmp/local-pypi/bin/activate
pip3 install -i http://localhost:8000/ hello-world1
Requirement already satisfied: hello-world1 in /tmp/local-pypi/lib/python3.6/site-packages
## Debina packaging