poetry
is currently the recommended tool for dependency management but "consider other tools such as pip when poetry does not meet your use case". If poetry
doesn't fit your use case, I recommend using virtualenvwrapper
for managing virtual environments and pip
for package management. On the other hand, if you're working on only a couple of projects, built-in venv
will do just fine.
poetry
¶pip
, virtualenv
, and packaging facilities under single CLIvirtualenvwrapper
¶virtualenvwrapper-win
virtualenv
pytest
¶There's unittest
module in Python Standard Library but the go-to test runner nowadays is definitely pytest
.
Some reasons to use pytest
:
fixtures
for writing reusable testing codemarkers
for splitting tests to different groups (e.g. smoke, run only on CI machine, etc) or skipping tests in certain conditionspytest-cov
for coverage reportingpytest-xdist
for speeding up test suit run time with parallelizationpytest
tox
¶tox
makes it simple to test your code against different Python interpreter/runtime and dependency versions. This is important when you're writing software which should support different Python versions, which is usually the case with library-like packages. On the other hand, if you're developing, say, a web application which will be deployed to a known target platform, testing against multiple different versions is usually not necessary. However, tox
makes it also possible to configure, for example, linting as part of tox
run. Thus, tox
may simplify the development workflow significantly by wrapping multiple different operations under a single command.
import this
The Zen of Python, by Tim Peters Beautiful is better than ugly. Explicit is better than implicit. Simple is better than complex. Complex is better than complicated. Flat is better than nested. Sparse is better than dense. Readability counts. Special cases aren't special enough to break the rules. Although practicality beats purity. Errors should never pass silently. Unless explicitly silenced. In the face of ambiguity, refuse the temptation to guess. There should be one-- and preferably only one --obvious way to do it. Although that way may not be obvious at first unless you're Dutch. Now is better than never. Although never is often better than *right* now. If the implementation is hard to explain, it's a bad idea. If the implementation is easy to explain, it may be a good idea. Namespaces are one honking great idea -- let's do more of those!
PEP8 (see also "for humans version") describes the style guidelines for Python code, you should follow them. Luckily, there are awesome tools that handle this for you while you focus on writing code, not formatting it.
Automatic code formatting is great but in addition to that, you should use static analyzer (linter) to detect potential pitfalls in your code.
pre-commit
¶Ideally, all project contributors should follow the best practices of the project, let it be e.g. respecting PEP8 or making sure there's no linting errors or security vulnerabilities in their change sets. However, as code formatters and linters are (mainly) local tools, this can not be guaranteed. pre-commit
let's you configure (.pre-commit-config.yaml file) a set of hooks that will be run as pre actions to a commit/push. After a developer has called once pre-commit install
, these hooks will be then automatically ran prior each commit/push.
Some general guidelines:
A few words about structuring your projects. If you're developing, say, a relative big business application, it makes sense to separate some of the non-core business logic packages into a separate project and publish that as separate package. This way the "main" repository doesn't get bloated and it's more approachable for newcomers. Additionally, there's a change that you (or someone else) can easily reuse this "separated" package in the future, which is often the case e.g. for different kinds of utility functionalities.
Let's take a practical example. If your team has two different applications which interact with the same third party, it's beneficial to implement a separate client library for communication with it. This way a change is needed only in one place (in the client library) if the third party decides to make a backwards incompatible change in their API.
cookiecutter
¶Cookiecutter is a tool which let's you create projects from predefined templates.
pre-commit
, tox
, and CI configuration)CI & CD belong to the best practices of software development without controversy, no matter what is the technology stack used for development. From Python point of view, CI is the place where we want to make sure that the other best practices described above are followed. For example, in bigger projects, it may not be even practical/possible to run the full test suite on developer's machine.
Tooling depends on which git repository manager option you've chosen and what kind of requirements you have. For example:
As there's a number of different editors and IDEs available, not to mention that everyone has their own preferences, I'll just focus on highlighting some of the features of my favorite IDE, PyCharm, which I highly recommend for Python development.
pytest
, e.g. run single tests / test classes / test modulesblack
These are especially useful with web applications as you'll get reports - and notifications - of runtime exceptions with full tracebacks and variable values. This information is often enough for identifying the root cause of the problem, which is a huge benefit considering the time required for implementing and deploying the fix.
logging
is part of the Standard Library