uvpy 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
uvpy/__init__.py ADDED
@@ -0,0 +1,29 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ uvpy - Portable Python App Framework
4
+
5
+ A framework for isolated Python apps with:
6
+ - Portable Python (optional)
7
+ - Isolated venvs per app (via uv)
8
+ - Offline installation from local pypi/
9
+ - Sandbox: localhost only, no telemetry
10
+ """
11
+
12
+ try:
13
+ from importlib.metadata import version as _get_version
14
+ __version__ = _get_version("uvpy")
15
+ except Exception:
16
+ __version__ = "0.1.0"
17
+
18
+ from .sandbox import activate as activate_sandbox
19
+ from .imports import try_import, require, is_available, LazyModule, optional_import
20
+
21
+ __all__ = [
22
+ "__version__",
23
+ "activate_sandbox",
24
+ "try_import",
25
+ "require",
26
+ "is_available",
27
+ "LazyModule",
28
+ "optional_import",
29
+ ]
uvpy/__main__.py ADDED
@@ -0,0 +1,13 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ uvpy - Entry point for python -m uvpy
4
+
5
+ Enables:
6
+ python -m uvpy --help
7
+ python -m uvpy hello
8
+ """
9
+ from .cli import main
10
+ import sys
11
+
12
+ if __name__ == "__main__":
13
+ sys.exit(main())
uvpy/app_runner.py ADDED
@@ -0,0 +1,89 @@
1
+ # -*- coding: utf-8 -*-
2
+ """
3
+ uvpy App Runner - Executes apps in their venv.
4
+
5
+ Called by uvpy via `uv run`:
6
+ uv run --directory apps/<app> python /path/to/app_runner.py <app_path> [args...]
7
+
8
+ This script:
9
+ 1. Activates the sandbox (security)
10
+ 2. Loads the app from main.py
11
+ 3. Parses CLI arguments
12
+ 4. Executes app.run(args)
13
+ """
14
+ import sys
15
+ import os
16
+ import argparse
17
+ import importlib.util
18
+ from pathlib import Path
19
+
20
+
21
+ def activate_sandbox() -> None:
22
+ """Activate the security sandbox."""
23
+ # sandbox.py is in the same directory as app_runner.py
24
+ runner_dir = Path(__file__).parent
25
+ sandbox_path = runner_dir / "sandbox.py"
26
+
27
+ if sandbox_path.exists():
28
+ spec = importlib.util.spec_from_file_location("sandbox", sandbox_path)
29
+ sandbox = importlib.util.module_from_spec(spec)
30
+ spec.loader.exec_module(sandbox)
31
+ sandbox.activate()
32
+
33
+
34
+ def load_app_module(app_path: Path):
35
+ """Load main.py of the app."""
36
+ main_py = app_path / "main.py"
37
+
38
+ if not main_py.exists():
39
+ print(f"ERROR: {main_py} not found", file=sys.stderr)
40
+ sys.exit(1)
41
+
42
+ spec = importlib.util.spec_from_file_location("main", main_py)
43
+ module = importlib.util.module_from_spec(spec)
44
+
45
+ # Add app directory to sys.path
46
+ sys.path.insert(0, str(app_path))
47
+
48
+ spec.loader.exec_module(module)
49
+ return module
50
+
51
+
52
+ def main() -> int:
53
+ """Main function of the App Runner."""
54
+ if len(sys.argv) < 2:
55
+ print("Usage: app_runner.py <app_path> [args...]", file=sys.stderr)
56
+ return 1
57
+
58
+ app_path = Path(sys.argv[1]).resolve()
59
+ app_args = sys.argv[2:]
60
+
61
+ # Activate sandbox (security)
62
+ activate_sandbox()
63
+
64
+ # Load app module
65
+ module = load_app_module(app_path)
66
+
67
+ # Create parser and register arguments
68
+ parser = argparse.ArgumentParser(
69
+ prog=app_path.name,
70
+ description=getattr(module, "__doc__", None)
71
+ )
72
+
73
+ if hasattr(module, "register"):
74
+ module.register(parser)
75
+
76
+ # Parse arguments
77
+ args = parser.parse_args(app_args)
78
+
79
+ # Execute app
80
+ if hasattr(module, "run"):
81
+ result = module.run(args)
82
+ return result if isinstance(result, int) else 0
83
+ else:
84
+ print(f"ERROR: App '{app_path.name}' has no run() function", file=sys.stderr)
85
+ return 1
86
+
87
+
88
+ if __name__ == "__main__":
89
+ sys.exit(main())