From b1cba30b3e3f5ffab7923935ad5e5a1b448695a3 Mon Sep 17 00:00:00 2001 From: Facundo Batista Date: Thu, 20 Apr 2023 10:07:14 -0300 Subject: [PATCH 1/2] Improved press release. --- PRESS_RELEASE.txt | 49 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/PRESS_RELEASE.txt b/PRESS_RELEASE.txt index fd92553..9835349 100644 --- a/PRESS_RELEASE.txt +++ b/PRESS_RELEASE.txt @@ -8,7 +8,7 @@ With PyEmpaq you can convert any Python project into a single `.pyz` file with a That single file is everything that needs to be distributed. When the final user executes it, the original project will be expanded, its dependencies installed in a virtualenv, and then executed. Note that no special permissions or privileges are required, as everything happens in the user environment. -Both the packaging and the execution are fully multiplatorm. This means that you can pack a project in Linux, Windows, Mac or whatever, and it will run ok in Linux, Windows, Mac or whatever. The only requirement is Python to be already installed. +Both the packaging and the execution are fully multiplatorm. This means that you can pack a project in Linux, Windows, MacOS or whatever, and it will run ok in Linux, Windows, MacOS or whatever. The only requirement is Python to be already installed. What's new in this version? @@ -30,14 +30,51 @@ What's new in this version? - Run tests (unit and integration) in Linux, MacOS and Windows. -You can check the whole documentation, including demos and examples, in the docs page: +For more details please [check the documentation](https://pyempaq.readthedocs.io/en/latest/) (which includes demos and examples). The project [exists in Github](https://github.com/facundobatista/pyempaq/). - https://pyempaq.readthedocs.io/en/latest/ +Enjoy, -The project: +. Facundo - https://github.com/facundobatista/pyempaq/ -Enjoy, +-- + + +Release de PyEmpaq 0.3 + +Estoy muy contento de anunciar el release de PyEmpaq 0.3. + +PyEmpaq es un simple pero poderoso empaquetador de Python para correr cualquier proyecto en cualquier lado.con las dependencias que tenga mientras sean instalables en un entorno virtual. + +Con PyEmpaq pueden convertir cualquier proyecto de Python en un archivo único `.pyz`, con todo el contenido del proyecto dentro. + +Ese único archivo es todo lo que necesita ser distribuido. Cuando la usuaria final lo ejecute, se expandirá el proyecto original, sus dependencias se instalarán en un entorno virtual, y se correrá. Como no se necesitan permisos o privilegios especiales, todo puede correr en cualquier entorno. + +Tanto el empaquetado como la ejecución son completamente multiplataformas. Esto significa que se puede empaquetar el proyecto en Linux, Windows, MacOS o donde sea, y correrá bien en Linux, Windows, MacOS o donde sea. El único requerimiento es tener Python instalado previamente. + + +¿Qué hay de nuevo en esta versión? + +- Agregué opciones 'include' y 'exclude' en la configuración para tener el control completo del contenido del proyecto empaquetado. + +- Ahora se reusa el directorio del proyecto existente sólo si se completó satisfactoriamente en una instalación previa. + +- Soporta declarar una versión mínima de Python para correr el proyecto empaquetado. + +- Se expone el path del archivo `.pyz` al proyecto cuando se ejecuta. + +- Ahora usa logging internamente para exponer mensajes a desarrolladores y usuaries. + +- Se configura correctamente el PATH en el entorno del comando final. + +- Agregué una opción -V/--version al empaquetador para solamente mostrar la versión y salir. + +- Los tests (de unidad e integración) se corren automáticamente en Linux, MacOS and Windows. + + +Para más detalles revisen [la documentación](https://pyempaq.readthedocs.io/en/latest/) (que incluye demos y ejemplos). El proyecto [está en Github](https://github.com/facundobatista/pyempaq/). + +Que lo disfruten. . Facundo + From 31827d5e94c89d6479fc81b31f2f7dc4a984cb2a Mon Sep 17 00:00:00 2001 From: Facundo Batista Date: Thu, 20 Apr 2023 11:22:11 -0300 Subject: [PATCH 2/2] Include packaging in the unpacker venv because it's not everywhere. --- pyempaq/main.py | 5 ++++- pyempaq/unpacker.py | 16 +++++++++------- requirements-dev.txt | 1 + tests/test_unpacker.py | 13 +++++++------ 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/pyempaq/main.py b/pyempaq/main.py index 4add6fa..fb47e39 100644 --- a/pyempaq/main.py +++ b/pyempaq/main.py @@ -33,6 +33,9 @@ # collected arguments Args = namedtuple("Args", "project_name basedir entrypoint requirement_files") +# dependencies needed for the unpacker to run ok +UNPACKER_DEPS = ["appdirs", "packaging"] + def get_pip(): """Ensure an usable version of `pip`.""" @@ -208,7 +211,7 @@ def pack(config): logger.debug("Building internal dependencies dir") venv_dir = tmpdir / "venv" pip = get_pip() - cmd = [pip, "install", "appdirs", f"--target={venv_dir}"] + cmd = [pip, "install", *UNPACKER_DEPS, f"--target={venv_dir}"] logged_exec(cmd) metadata = prepare_metadata(origdir, config) diff --git a/pyempaq/unpacker.py b/pyempaq/unpacker.py index cd653a7..35ddeb8 100644 --- a/pyempaq/unpacker.py +++ b/pyempaq/unpacker.py @@ -15,10 +15,9 @@ import time import venv import zipfile +from types import ModuleType from typing import List, Dict, Any -from packaging import version - from pyempaq.common import find_venv_bin, logged_exec @@ -135,7 +134,7 @@ def setup_project_directory( (project_dir / COMPLETE_FLAG_FILE).touch() -def restrictions_ok(restrictions: Dict[str, Any]) -> bool: +def restrictions_ok(version: ModuleType, restrictions: Dict[str, Any]) -> bool: """Enforce the unpacking restrictions, if any; return True if all ok to continue.""" if not restrictions: return True @@ -165,12 +164,15 @@ def run(): zf = zipfile.ZipFile(pyempaq_filepath) metadata = json.loads(zf.read("metadata.json").decode("utf8")) log("Loaded metadata: %s", metadata) - if not restrictions_ok(metadata["unpack_restrictions"]): - exit(1) - # load appdirs from the builtin venv + # load appdirs and packaging from the builtin venv (not at top of file because + # paths needed to be fixed) sys.path.insert(0, f"{pyempaq_filepath}/venv/") - import appdirs # NOQA: this is an import not at top of file because paths needed to be fixed + import appdirs # NOQA + from packaging import version # NOQA + + if not restrictions_ok(version, metadata["unpack_restrictions"]): + exit(1) pyempaq_dir = pathlib.Path(appdirs.user_data_dir()) / 'pyempaq' pyempaq_dir.mkdir(parents=True, exist_ok=True) diff --git a/requirements-dev.txt b/requirements-dev.txt index eb1955b..03a4986 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,6 +2,7 @@ flake8 logassert +packaging pydocstyle pytest pytest-subprocess diff --git a/tests/test_unpacker.py b/tests/test_unpacker.py index 7108931..f0b4e37 100644 --- a/tests/test_unpacker.py +++ b/tests/test_unpacker.py @@ -12,6 +12,7 @@ import pytest from logassert import Exact, NOTHING +from packaging import version import pyempaq.unpacker from pyempaq.unpacker import ( @@ -228,14 +229,14 @@ def test_projectdir_requirements(tmp_path, logs): @pytest.mark.parametrize("restrictions", [None, {}]) def test_enforcerestrictions_empty(restrictions, logs): """Support for no restrictions.""" - ok = restrictions_ok(restrictions) + ok = restrictions_ok(version, restrictions) assert ok is True assert NOTHING in logs.any_level def test_enforcerestrictions_pythonversion_smaller(logs): """Enforce minimum python version: smaller version.""" - ok = restrictions_ok({"minimum_python_version": "0.8"}) + ok = restrictions_ok(version, {"minimum_python_version": "0.8"}) current = platform.python_version() assert ok is True assert f"Checking minimum Python version: indicated='0.8' current={current!r}" in logs.info @@ -244,7 +245,7 @@ def test_enforcerestrictions_pythonversion_smaller(logs): def test_enforcerestrictions_pythonversion_bigger_enforced(logs): """Enforce minimum python version: bigger version.""" - ok = restrictions_ok({"minimum_python_version": "42"}) + ok = restrictions_ok(version, {"minimum_python_version": "42"}) current = platform.python_version() assert ok is False assert f"Checking minimum Python version: indicated='42' current={current!r}" in logs.info @@ -254,7 +255,7 @@ def test_enforcerestrictions_pythonversion_bigger_enforced(logs): def test_enforcerestrictions_pythonversion_bigger_ignored(logs, monkeypatch): """Ignore minimum python version for the bigger version case.""" monkeypatch.setenv("PYEMPAQ_IGNORE_RESTRICTIONS", "minimum-python-version") - ok = restrictions_ok({"minimum_python_version": "42"}) + ok = restrictions_ok(version, {"minimum_python_version": "42"}) current = platform.python_version() assert ok is True assert f"Checking minimum Python version: indicated='42' current={current!r}" in logs.info @@ -266,7 +267,7 @@ def test_enforcerestrictions_pythonversion_bigger_ignored(logs, monkeypatch): def test_enforcerestrictions_pythonversion_current(logs): """Enforce minimum python version: exactly current version.""" current = platform.python_version() - ok = restrictions_ok({"minimum_python_version": current}) + ok = restrictions_ok(version, {"minimum_python_version": current}) assert ok is True assert ( f"Checking minimum Python version: indicated={current!r} current={current!r}" in logs.info @@ -276,5 +277,5 @@ def test_enforcerestrictions_pythonversion_current(logs): def test_enforcerestrictions_pythonversion_good_comparison(logs): """Enforce minimum python version using a proper comparison, not strings.""" - ok = restrictions_ok({"minimum_python_version": "3.0009"}) + ok = restrictions_ok(version, {"minimum_python_version": "3.0009"}) assert ok is True