Mira esta ejemplo de cómo configurar un proyecto Python con lo esencial para
comenzar rápidamente, pero con la capacidad de ajustar y escalar conforme las
necesidades aumenten.
pyproject.toml
: archivo de configuración estándar PEP-518 para
proyectos Python.Makefile
: Se utiliza para automatizar tareas como testing, build, installs,
entre otros.__version__
(opcional): Es útil para mantener un registro de las distintas
versiones de tu proyecto.
Mi estrategia favorita es comenzar con todos los elementos en un solo archivo y
luego, a medida que el proyecto crezca, dividirlos en la estructura de carpetas
basada en src
. No me preocuparia por esta reestructuración hasta que sea
verdaderamente necesario.
Aqui uso setuptools-scm
para obtener una versión automática de la librería
basada en los tags de Git, los cuales deben seguir el estándar PEP-440.
Esto es lo que use para crear [takt
][takt], con el que hasta ahora estoy
muy contento:
1
2
3
4
5
| mkdir -p takt/tests
touch takt/README.md
touch takt/Makefile
touch takt/pyproject.toml
touch takt/takt.py
|
Esto es lo minimo que se necesita para empezar un proyecto python.
Este archivo es una especificación moderna de empaque para proyectos de Python,
según PEP-518. Sirve para declarar las dependencias que necesitas
para construir tu proyecto desde la fuente. Esta es una alternativa al uso de
setup.py
y requirements.txt
en proyectos Python.
pyproject.toml
es como un archivo de configuración centralizado para muchas
de las herramientas que podrías usar en tu proyecto Python. Su uso es cada vez
más común a medida que dichas herramientas migran su soporte al archivo
pyproject.toml
.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| [build-system]
requires = ["setuptools>=60", "setuptools-scm>=8.0"]
build-backend = "setuptools.build_meta"
[project]
name = "takt"
dynamic = ["version"]
authors = [{name="Max Greco", email="asdf0x2199@gmail.com"}]
readme = "README.md"
requires-python = ">=3.6"
dependencies = ["rich", "typer", "pandas"]
license = {file = "LICENSE"}
description = "Takt is a CLI tool for tracking time."
[project.scripts]
takt = "takt:app"
[tool.setuptools_scm]
|
Asignar un número de versión o __version__
a un proyecto es un paso opcional,
pero definitivamente beneficioso. Lo que hace es facilitar la identificación
del número de versión de la biblioteca, sin la necesidad de generar un archivo
adicional. Por supuesto, si se prefiere seguir esta ruta, se puede. Simplemente
es una opción más en el amplio espectro de posibilidades que el desarrollo
proporciona.
1
2
3
4
5
6
7
| from importlib.metadata import version, PackageNotFoundError
try:
__version__ = version("package-name")
except PackageNotFoundError:
# package is not installed
pass
|
Este Makefile
es una joya, viene autodocumentado por lo que no hay que
ocuparse de mantener un help actualizado. Tomate tu tiempo para leerlo y
entenderlo, es bastante facil.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
| # variables
PYVER := 3.10
venv := .venv
python := $(venv)/bin/python
pip := $(venv)/bin/pip
##@ Utility
.PHONY: help
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make <target>\033[36m\033[0m\n"} /^[a-zA-Z\._-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Setup
$(venv):
@if [ -x "`command -v conda`" ]; then \
conda create --prefix $(venv) python=$(PYVER) -y -q; \
else \
python$(PYVER) -m venv $(venv); \
fi
.PHONY: install
install: $(venv) ## install
$(pip) install . -r requirements.txt
.PHONY: push
push: tag ## push to origin a new tag, e.g. make push v=<version>
git push origin main
git push --tags
##@ Development
.PHONY: dev
dev: $(venv) ## install dev mode
$(pip) install -e . -r requirements-dev.txt
.PHONY: test
test: $(venv) ## run tests
@$(pip) -q install pytest
$(python) -m pytest tests
.PHONY: lint
lint: $(venv) ## run linting check
@$(pip) -q install ruff
$(python) -m ruff ./src
.PHONY: black
black: $(venv) ## apply black to source code
@$(pip) -q install black
$(python) -m black -l79
.PHONY: requirements.txt
requirements.txt: ## generate requirements.txt, e.g. make requirements.txt
@test -d /tmp/venv && rm -r /tmp/venv || true
@$(python) -m venv /tmp/venv
@/tmp/venv/bin/python -m pip -q install pip -U
@/tmp/venv/bin/python -m pip -q install . --progress-bar off
@/tmp/venv/bin/python -m pip freeze > requirements.txt
$(MAKE) fix-requirements.txt
.PHONY: fix-requirements.txt
fix-requirements.txt: ## fix requirements.txt using GH_TOKEN variable for privates repos.
@if [ "$(shell uname -s)" = "Linux" ]; then \
sed -i 's/git+ssh:\/\/git@/git+https:\/\/$${GH_TOKEN}@/' requirements.txt; \
sed -i '/file:/d' requirements.txt; \
elif [ "$(shell uname -s)" = "Darwin" ]; then \
sed -i '' -e 's/git+ssh:\/\/git@/git+https:\/\/$${GH_TOKEN}@/' requirements.txt; \
sed -i '' -e '/file:/d' requirements.txt; \
fi
@cat requirements.txt
|