Desarrollo¶
El complemento tiene dos conjuntos de pruebas.
tests/corecubre la lógica de STAC, del registro, de PMTiles, de GeoParquet y de descarga enportolan_registry_qgis/core. Ese paquete no importa ni QGIS ni GDAL, así que el conjunto se ejecuta en el entorno de uv.tests/in_qgisnecesita PyQGIS. Crea un catálogo pequeño con GDAL y DuckDB y lo sirve en la interfaz de bucle local. Después, las pruebas ejercitan el código de red, las capas, las descargas y la ventana.
uv sync
uv run pytest
Para el conjunto de QGIS, cree un entorno virtual sobre el Python que tiene PyQGIS:
uv venv --python /usr/bin/python3 --system-site-packages .venv-qgis
VIRTUAL_ENV=.venv-qgis uv pip install pytest pytest-timeout duckdb babel pytest-cov
QT_QPA_PLATFORM=offscreen .venv-qgis/bin/python -m pytest tests/in_qgis
Añada -m network para ejecutar las comprobaciones en vivo contra el registro y dos catálogos publicados.
La CI ejecuta tests/in_qgis en las imágenes Docker oficiales de QGIS 3.34, 3.44 y 4.2. QGIS 3.34 es la versión más antigua que admite el complemento, y 4.2 cubre Qt6.
Para medir el tiempo de renderizado de PMTiles con un archivo remoto, ejecute la prueba de rendimiento con el mismo Python. La opción --baseline restaura el transporte de teselas de la versión 0.1.1 para comparar.
QT_QPA_PLATFORM=offscreen .venv-qgis/bin/python \
scripts/bench_tiles.py
QT_QPA_PLATFORM=offscreen .venv-qgis/bin/python \
scripts/bench_tiles.py --baseline
Barridos del registro¶
Las pruebas usan catálogos que crea el complemento. Los scripts de barrido, en cambio, ejecutan el complemento contra cada catálogo del registro en vivo e informan de cada comprobación que falla.
scripts/sweep_registry.pyejecuta la ruta de lectura del núcleo con uv. Para cada colección, prueba los archivos que hay detrás de Ver en el mapa y Cargar datos completos, y planifica la lectura del GeoParquet con DuckDB. También lee los estilos, la miniatura y las rutas de descarga.scripts/sweep_qgis.pyañade los destinos de cada colección como capas de QGIS con sus estilos y luego renderiza cada capa. Informa de las capas no válidas, los renderizados en blanco y las advertencias de estilo.
uv run python scripts/sweep_registry.py --out sweep
QT_QPA_PLATFORM=offscreen .venv-qgis/bin/python \
scripts/sweep_qgis.py --out sweep-qgis
Cada script escribe sweep.md y sweep.json en su carpeta de salida. Use --only con identificadores de catálogo para barrer unos pocos catálogos. El flujo de trabajo Registry sweep ejecuta los dos scripts cada noche y sube los informes. Un fallo ahí no bloquea una fusión.
Controles de calidad¶
Pre-commit ejecuta estas comprobaciones, y la CI las vuelve a ejecutar en cada pull request. Un cambio debe superar cada una.
| Control | Umbral |
|---|---|
| Ruff | El conjunto de reglas de pyproject.toml, con las reglas de pylint, pytest y tryceratops. Complejidad de McCabe de 10 o menos. |
| mypy | Modo estricto en el paquete y en scripts. |
| vulture | Ningún nombre sin usar con una confianza del 60 % o más. |
| xenon en el paquete | Cada bloque en el rango B o mejor. Cada módulo y la media en el rango A. |
| xenon en las pruebas y los scripts | Cada bloque en el rango C o mejor. Cada módulo en el rango B o mejor, y la media en el rango A. |
| jscpd | Ninguna copia de 50 tokens y 5 líneas o más. |
| Docstrings | 5 líneas o menos. Ningún historial de cambios en un docstring o un comentario. |
| import-linter | El núcleo no importa código de QGIS, Qt ni GDAL, ni ninguna de las capas de QGIS. qgis_io no importa nada de gui. |
| Cobertura, conjunto de uv | El 99 % del núcleo. |
| Cobertura, conjunto de QGIS | El 87 % de plugin.py, gui y qgis_io. |
| diff-cover | El 90 % de las líneas modificadas. Solo en la CI. |
Ejecute los controles uno a uno:
uv run ruff check .
uv run mypy
uv run vulture
uv run xenon --max-absolute=B --max-modules=A \
--max-average=A portolan_registry_qgis
uv run xenon --max-absolute=C --max-modules=B \
--max-average=A tests scripts
uvx prek run jscpd --all-files
uv run python scripts/docstring_check.py
uv run lint-imports
uv run pytest -n 4 --cov=portolan_registry_qgis
El conjunto de QGIS toma su configuración de cobertura de un archivo propio:
QT_QPA_PLATFORM=offscreen .venv-qgis/bin/python \
-m pytest -p no:cacheprovider tests/in_qgis \
--cov=portolan_registry_qgis \
--cov-config=tests/in_qgis/coverage.ini \
--cov-report=term-missing --cov-fail-under=87
Para ejecutar todos los hooks de las dos etapas:
uvx prek run --all-files
uvx prek run --all-files --hook-stage pre-push
Traducciones¶
El complemento y este sitio están en inglés, español y francés. El inglés es el idioma de origen, y un cambio en un texto en inglés necesita las traducciones al español y al francés en la misma pull request. Pre-commit y la CI ejecutan scripts/i18n.py check, que falla hasta que los dos idiomas estén al día.
El complemento traduce su texto con gettext. Envuelva cada cadena que lee una persona en _() de portolan_registry_qgis.core.i18n, y use count() para un texto con un número:
from portolan_registry_qgis.core.i18n import _, count
label.setText(_("Zoom to"))
status.setText(_("Could not open {url}").format(url=url))
row.setText(count("{n} file", "{n} files", total))
Como el complemento elige el idioma después de que Python importa sus módulos, una constante de módulo almacena su texto en inglés dentro de N_(), y el código que la muestra llama a _(). Los marcadores de posición tienen nombre, lo que permite que una traducción los reordene. Babel copia un comentario que empieza por # Translators:, en la línea anterior a una llamada, al catálogo junto al mensaje.
Cuando cambie un texto en inglés, regenere los catálogos y traduzca las entradas nuevas:
uv run python scripts/i18n.py update
uv run python scripts/i18n.py check
update extrae el inglés a portolan_registry_qgis/locale/messages.pot y lo combina con el messages.po de cada idioma. Una cadena nueva llega sin traducción. Una cadena modificada llega marcada como #, fuzzy, con su traducción anterior. Escriba la traducción, quite la marca fuzzy y luego ejecute update de nuevo. Esa ejecución compila messages.mo y escribe las líneas description[es] y about[es] de metadata.txt, que muestra el administrador de complementos de QGIS.
Cada página de docs/ tiene una traducción en docs-i18n/<lang>/ con la misma ruta. Su front matter registra el SHA-256 de la página en inglés en source_sha256. Cuando la página en inglés cambia, check muestra el hash nuevo. Traduzca el cambio y luego defina el hash nuevo. Los títulos de navegación y la descripción del sitio vienen de los catálogos, con el contexto docs.
Construya los tres sitios con:
uv sync --group docs
uv run python scripts/i18n.py build-docs
El complemento usa el idioma de la interfaz de QGIS, de Configuración > Opciones > General. Para añadir un idioma, añada su código a LANGUAGES en core/i18n.py y sus separadores de dígitos a _GROUP y _DECIMAL. Después añádalo a extra.alternate en mkdocs.yml, ejecute update y traduzca todos los mensajes y páginas.
Publicación¶
- Liste los cambios bajo
## UnreleasedenCHANGELOG.md, como una lista plana sin subtítulos. qgis-plugin-ci copia la lista en el registro de cambios que muestra el administrador de complementos de QGIS, y se detiene en el siguiente encabezado. - Ejecute
uv run cz bump. Actualizapyproject.tomlymetadata.txt, mueve las notas bajo un encabezado## <version> - <date>y luego etiqueta el commit. El bump se detiene cuando las notas de Unreleased están vacías. - Envíe el commit y la etiqueta, y luego publique una versión de GitHub a partir de la etiqueta.
.github/workflows/release.ymlempaqueta el complemento conqgis-plugin-ci, adjunta el zip a la versión y lo sube al repositorio oficial de complementos de QGIS.