Machine setup
Python is undergoing a shift in project management tooling. It is a slow shift that has occurred over the course of years, and will take years more to complete. In v3.12 distutils was removed for reasons discussed in PEP 632. The preference is now for setuptools (or another "build backend") to be used instead.
asdf
Ensure you have python on your machine. I use asdf for language version management in general
asdf plugin add python
asdf install python $(asdf latest python)
asdf global python $(asdf latest python)
Create a python project directory. I'll call this example one proj
mkdir proj
cd proj
venv
Setup venv, which isolates your project changes from your global python environment. venv
is library module included in most Python installations. You run library modules via python -m
. The below command creates a venv/
folder within your project for storing project-only virtual environment details. (It is also common to call it ./.venv/
if you prefer.)
python -m venv ./venv
You can then activate this environment as follows.
source ./venv/bin/activate
You can confirm this worked by seeing which python
you are using before and after activation. Before, it will be your global python, after, it will point to a local python, ./proj/venv/bin/python
.
When you are done you can deactivate as follows.
deactivate
While in the virtual environment, calls to pip
, etc., only modify the virtual environment.
pyproject.toml, build, and setuptools
Next, install build which is the preferred "build frontend" for the Python ecosystem (to the point where I'm not aware of an alternative). Don't forget to do this in your activate
d virtual env.
pip install build
Also setup your initial pyproject.toml
. This is a relatively new addition to python project management. It was initiated by PEP 518 and PEP 621, with PEP 621 being created as recently as 2020. See the official specification and gentle introduction for more.
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "mypackage"
version = "0.0.1"
dependencies = [
"requests",
'importlib-metadata; python_version<"3.10"',
]
Note the presence of setuptools
in the [build-system]
section. Setuptools is the "build backend" that build
defaults to. build
will read the pyproject.toml
and use venv
and setuptools
in it's own environment when building, meaning we don't ever have to pip install setuptools
ourselves.
package folder
As per the setuptools quickstart guide, the expected directory structure is a nested folder that is the actual package to be built. It is common to name that directory the same as your parent directory.
/proj/
/proj/pyproject.toml
/proj/README.md
/proj/proj
/proj/proj/__init__.py
# proj/proj/__init__.py
print "hello"
Running python -m build
will now build your project. You should get as output a dist/
folder and a mypackage.egg-info/
.
Next steps
If you want to upload your project to PyPI, it seems the recommended tool is twine. I haven't ever done this myself so I won't comment much more on it.
If you are just running local projects you don't ever even need to run python -m build
, since you aren't distributing it. Certain PaaS environments might not require a dist build either. It might still make sense to make your project installable even if you are building something like a Flask web app.
It seems that pyproject.toml
will be the future of Python, so even if you aren't distributing your project, it still makes sense to lean in to these tools, at least as far as I can tell. Relatedly, some of the older solutions are recommending similarly. For example, see the section #Do not use _just_ `pip` and requirements.txt for project management
Do not use just pip
and requirements.txt for project management
pip
itself has a guide on this topic: Pip is not a workflow management tool. They recommend using tools like build
when building, and for package/project/workflow management they recommend the official packaging user guide, which is a core source in my Python#Machine setup notes.
Flask web app
Flask is a web server framework.
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
flask run
gunicorn
I don't claim to understand everything going on here, but gunicorn seems to be the default wsgi server. (WSGI appears to be a python web-server-to-web-application interface.)
gunicorn -w 4 'app:app'
pandas
See my note on pandas
Lists
https://docs.python.org/3/library/stdtypes.html#lists
List comprehensions
https://docs.python.org/3/tutorial/datastructures.html#list-comprehensions