Skip to content

Commit

Permalink
feat: integrate pycify (#22)
Browse files Browse the repository at this point in the history
Co-authored-by: Tushar Sadhwani <[email protected]>
  • Loading branch information
NobleMathews and tusharsadhwani authored Jun 17, 2024
1 parent e2f1d54 commit cb34a60
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 4 deletions.
3 changes: 2 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = packaged
version = 0.5.3
version = 0.6.0
description = The easiest way to ship python applications.
long_description = file: README.md
long_description_content_type = text/markdown
Expand Down Expand Up @@ -28,6 +28,7 @@ install_requires =
yen>=0.4.2
tomli>=1.1.0; python_version<'3.11'
yaspin>=2.5.0
pycify>=1.2.0
python_requires = >=3.8
package_dir = =src

Expand Down
1 change: 1 addition & 0 deletions setup.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from setuptools import setup

setup()
15 changes: 15 additions & 0 deletions src/packaged/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import yen.github
from yaspin import yaspin

from pycify import replace_py_with_pyc

if TYPE_CHECKING:
from yaspin.core import Yaspin

Expand Down Expand Up @@ -48,6 +50,8 @@ def create_package(
startup_command: str,
python_version: str,
quiet: bool = False,
pyc: bool = False,
ignore_file_patterns: list[str] | None = None,
) -> None:
"""Create the makeself executable, with the startup script in it."""
if os.path.exists(output_path):
Expand All @@ -59,6 +63,17 @@ def create_package(
if not os.path.isdir(source_directory):
raise SourceDirectoryNotFound(source_directory)

if pyc:
created_pyc_files = replace_py_with_pyc(
source_directory,
python_version=python_version,
ignore_file_patterns=ignore_file_patterns,
)
if not created_pyc_files:
print("No .pyc files were created.", file=sys.stderr)
else:
print(f"Created {len(created_pyc_files)} .pyc files.")

startup_script_name = "_packaged_startup.sh"
startup_script_path = os.path.join(source_directory, startup_script_name)

Expand Down
1 change: 1 addition & 0 deletions src/packaged/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Support executing the CLI by doing `python -m packaged`."""

from __future__ import annotations

from packaged.cli import cli
Expand Down
14 changes: 14 additions & 0 deletions src/packaged/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,18 @@ def cli(argv: list[str] | None = None) -> int:
action="store_true",
default="CI" in os.environ,
)
parser.add_argument(
"--pyc",
help="Replace .py files with .pyc files",
action="store_true",
default=False,
)
parser.add_argument(
"--ignore-file-patterns",
help="List of file patterns to ignore when using --pyc",
nargs="+",
default=["setup.py"],
)
args = parser.parse_args(argv)
config = Config(**vars(args))

Expand All @@ -85,6 +97,8 @@ def cli(argv: list[str] | None = None) -> int:
config.startup_command,
config.python_version,
config.quiet,
config.pyc,
config.ignore_file_patterns,
)
except SourceDirectoryNotFound as exc:
error(f"Folder {exc.directory_path!r} does not exist.")
Expand Down
4 changes: 4 additions & 0 deletions src/packaged/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ class Config:
startup_command: str
python_version: str
quiet: bool
pyc: bool
ignore_file_patterns: list[str] | None


CONFIG_NAME = "./packaged.toml"
Expand Down Expand Up @@ -56,6 +58,8 @@ def parse_config(source_directory: str) -> Config:
config_data["startup_command"],
config_data.get("python_version", "3.12"),
config_data.get("quiet", "CI" in os.environ),
config_data.get("pyc", False),
config_data.get("ignore_file_patterns"),
)
except KeyError as exc:
key = exc.args[0]
Expand Down
64 changes: 63 additions & 1 deletion tests/cli_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ def test_cli(monkeypatch: MonkeyPatch) -> None:
"python -m foo",
packaged.DEFAULT_PYTHON_VERSION,
False,
False,
["setup.py"],
)

with mock.patch.object(packaged.cli, "create_package") as mocked:
Expand All @@ -31,7 +33,14 @@ def test_cli(monkeypatch: MonkeyPatch) -> None:

# specified python version
mocked.assert_called_with(
None, "./baz", "pip install baz", "python -m baz", "3.10", False
None,
"./baz",
"pip install baz",
"python -m baz",
"3.10",
False,
False,
["setup.py"],
)

with mock.patch.object(packaged.cli, "create_package") as mocked:
Expand All @@ -52,6 +61,8 @@ def test_cli(monkeypatch: MonkeyPatch) -> None:
"python src/mypackage/cli.py",
packaged.DEFAULT_PYTHON_VERSION,
False,
False,
["setup.py"],
)
args = mocked.call_args[0]
assert args[0].endswith("/mypackage")
Expand All @@ -70,6 +81,8 @@ def test_cli(monkeypatch: MonkeyPatch) -> None:
"python some.py",
packaged.DEFAULT_PYTHON_VERSION,
True,
False,
["setup.py"],
)

# Test --quiet when CI is true, regardless of if the flag is passed
Expand All @@ -85,6 +98,8 @@ def test_cli(monkeypatch: MonkeyPatch) -> None:
"python some.py",
packaged.DEFAULT_PYTHON_VERSION,
True,
False,
["setup.py"],
)
monkeypatch.setattr(os, "environ", {"CI": "1"})
with mock.patch.object(packaged.cli, "create_package") as mocked:
Expand All @@ -100,4 +115,51 @@ def test_cli(monkeypatch: MonkeyPatch) -> None:
"python some.py",
packaged.DEFAULT_PYTHON_VERSION,
True,
False,
["setup.py"],
)

# unset CI
monkeypatch.setattr(os, "environ", {})
with mock.patch.object(packaged.cli, "create_package") as mocked:
packaged.cli.cli(
["./some", "pip install some", "python some.py", "./some.bin", "--pyc"]
)

# pyc is True
mocked.assert_called_with(
mock.ANY,
"./some",
"pip install some",
"python some.py",
packaged.DEFAULT_PYTHON_VERSION,
False,
True,
["setup.py"],
)

with mock.patch.object(packaged.cli, "create_package") as mocked:
packaged.cli.cli(
[
"./some",
"pip install some",
"python some.py",
"./some.bin",
"--pyc",
"--ignore-file-patterns",
"foo.py",
"test/*.py",
]
)

# pyc is True and ignore_file_patterns is ['foo.py', 'test/*.py']
mocked.assert_called_with(
mock.ANY,
"./some",
"pip install some",
"python some.py",
packaged.DEFAULT_PYTHON_VERSION,
False,
True,
["foo.py", "test/*.py"],
)
11 changes: 9 additions & 2 deletions tests/end_to_end/packaged_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ def build_package(
output_path: str,
build_command: str,
startup_command: str,
*,
create_pyc: bool = False,
) -> Iterator[None]:
"""Builds the package, but also delete it afterwards."""
try:
Expand All @@ -27,6 +29,7 @@ def build_package(
build_command,
startup_command,
python_version=packaged.DEFAULT_PYTHON_VERSION,
pyc=create_pyc,
)
yield
finally:
Expand All @@ -50,14 +53,18 @@ def test_just_python() -> None:


def test_numpy_pandas() -> None:
"""Packages `numpy_pandas` to test packaging the math stack."""
"""
Packages `numpy_pandas` to test packaging the math stack.
Also pass `--pyc` to ensure that works too.
"""
package_path = os.path.join(TEST_PACKAGES, "numpy_pandas")
executable_path = "./numpy_pandas.bin"
with build_package(
package_path,
executable_path,
"pip install numpy pandas",
"python somefile.py",
"python somefile.pyc",
create_pyc=True,
):
assert "0 -2.222222\ndtype: float64" in get_output(executable_path)

Expand Down
1 change: 1 addition & 0 deletions tests/end_to_end/test_packages/configtest/setup.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from setuptools import setup

setup()

0 comments on commit cb34a60

Please sign in to comment.