evok 0.1.0__tar.gz

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.
evok-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ella Inng
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
evok-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,110 @@
1
+ Metadata-Version: 2.4
2
+ Name: evok
3
+ Version: 0.1.0
4
+ Summary: Pure-Python high-performance packaging engine and virtualization runtime
5
+ Author: ellainng
6
+ Author-email: ellainng <299958882+ellainng@users.noreply.github.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Requires-Python: >=3.12
10
+ Description-Content-Type: text/markdown
11
+
12
+ # Evok (`ev`)
13
+
14
+ [![CI](https://github.com/wispsy/evok/actions/workflows/ci.yml/badge.svg)](https://github.com/wispsy/evok/actions/workflows/ci.yml)
15
+ [![Python Version](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://python.org)
16
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
17
+
18
+ > **Pure-Python high-performance package manager and zero-venv virtualization runtime.**
19
+
20
+ Evok demonstrates that a clean-slate Python implementation leveraging modern OS primitives and stdlib capabilities can reach ~80% of `uv`'s speed while delivering native capabilities that compiled binaries cannot provide: first-class in-process APIs, zero-venv `sys.meta_path` virtualization, dynamic AST dependency inference, and single-file zero-binary `.pyz` bootstrapping.
21
+
22
+ ---
23
+
24
+ ## Key Highlights
25
+
26
+ - **Zero-Copy Reflink Cache**: Unpacks wheels once into a global cache and installs in milliseconds using macOS APFS `clonefile`, Linux `FICLONE`, and hardlink (`os.link`) fallbacks.
27
+ - **Bit-Packed PEP 440 Arithmetic**: Encodes release segments and lifecycle stages into single 64-bit scalar integers for microsecond comparisons.
28
+ - **Async Metadata & Range Tail-Reads**: Fetches package metadata from remote ZIP central directories using HTTP Range requests without downloading full wheels.
29
+ - **Zero-Venv Virtualization**: Run code with in-process `sys.meta_path` hooks that load dependencies directly from the cache without creating a `.venv` directory on disk.
30
+ - **AST Dependency Scanner**: Scans project source code to automatically detect third-party imports, flag missing packages, and prune unused/dead dependencies.
31
+ - **Pure-Python Wheel & Sdist Builder**: Standards-compliant PEP 427 wheel generator, PEP 625 sdist packager, and single-file `.pyz` executable bundler.
32
+
33
+ ---
34
+
35
+ ## Quickstart
36
+
37
+ ### Installation
38
+
39
+ Evok runs on Python 3.12+ with zero external runtime dependencies:
40
+
41
+ ```bash
42
+ # Using uv
43
+ uv pip install evok
44
+
45
+ # Or via pip
46
+ pip install evok
47
+ ```
48
+
49
+ ### Command-Line Usage (`ev`)
50
+
51
+ ```bash
52
+ # Initialize a new project
53
+ ev init my-app
54
+
55
+ # Inspect AST imports and compare with pyproject.toml
56
+ ev scan
57
+
58
+ # Automatically prune unused dependencies
59
+ ev prune
60
+
61
+ # Build standard wheel, sdist, and standalone zipapp
62
+ ev build --zipapp
63
+
64
+ # Run a script with in-process zero-venv dependency virtualization
65
+ ev run script.py
66
+
67
+ # Check platform reflink support and runtime info
68
+ ev info
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Programmatic Python API
74
+
75
+ Evok is built as a first-class Python library:
76
+
77
+ ```python
78
+ from evok import Environment, InMemoryProvider, Resolver
79
+
80
+ # 1. Dependency Resolution
81
+ provider = InMemoryProvider(
82
+ {
83
+ "httpx": {"0.27.0": ["httpcore>=1.0.0"]},
84
+ "httpcore": {"1.0.5": []},
85
+ }
86
+ )
87
+ resolver = Resolver(provider=provider)
88
+ graph = resolver.resolve(["httpx>=0.24.0"])
89
+ print(graph.get("httpx").version) # 0.27.0
90
+
91
+ # 2. Ephemeral Zero-Venv Execution
92
+ with Environment.ephemeral(graph) as env:
93
+ mod = env.import_module("httpx")
94
+ ```
95
+
96
+ ---
97
+
98
+ ## Documentation
99
+
100
+ - [System Architecture](docs/architecture.md)
101
+ - [CLI Reference](docs/cli.md)
102
+ - [Python API Reference](docs/api.md)
103
+ - [Performance & Bottleneck Analysis](docs/benchmarks.md)
104
+ - [Implementation Plan](IMPLEMENTATION_PLAN.md)
105
+
106
+ ---
107
+
108
+ ## License
109
+
110
+ MIT License.
evok-0.1.0/README.md ADDED
@@ -0,0 +1,99 @@
1
+ # Evok (`ev`)
2
+
3
+ [![CI](https://github.com/wispsy/evok/actions/workflows/ci.yml/badge.svg)](https://github.com/wispsy/evok/actions/workflows/ci.yml)
4
+ [![Python Version](https://img.shields.io/badge/python-3.12%2B-blue.svg)](https://python.org)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)
6
+
7
+ > **Pure-Python high-performance package manager and zero-venv virtualization runtime.**
8
+
9
+ Evok demonstrates that a clean-slate Python implementation leveraging modern OS primitives and stdlib capabilities can reach ~80% of `uv`'s speed while delivering native capabilities that compiled binaries cannot provide: first-class in-process APIs, zero-venv `sys.meta_path` virtualization, dynamic AST dependency inference, and single-file zero-binary `.pyz` bootstrapping.
10
+
11
+ ---
12
+
13
+ ## Key Highlights
14
+
15
+ - **Zero-Copy Reflink Cache**: Unpacks wheels once into a global cache and installs in milliseconds using macOS APFS `clonefile`, Linux `FICLONE`, and hardlink (`os.link`) fallbacks.
16
+ - **Bit-Packed PEP 440 Arithmetic**: Encodes release segments and lifecycle stages into single 64-bit scalar integers for microsecond comparisons.
17
+ - **Async Metadata & Range Tail-Reads**: Fetches package metadata from remote ZIP central directories using HTTP Range requests without downloading full wheels.
18
+ - **Zero-Venv Virtualization**: Run code with in-process `sys.meta_path` hooks that load dependencies directly from the cache without creating a `.venv` directory on disk.
19
+ - **AST Dependency Scanner**: Scans project source code to automatically detect third-party imports, flag missing packages, and prune unused/dead dependencies.
20
+ - **Pure-Python Wheel & Sdist Builder**: Standards-compliant PEP 427 wheel generator, PEP 625 sdist packager, and single-file `.pyz` executable bundler.
21
+
22
+ ---
23
+
24
+ ## Quickstart
25
+
26
+ ### Installation
27
+
28
+ Evok runs on Python 3.12+ with zero external runtime dependencies:
29
+
30
+ ```bash
31
+ # Using uv
32
+ uv pip install evok
33
+
34
+ # Or via pip
35
+ pip install evok
36
+ ```
37
+
38
+ ### Command-Line Usage (`ev`)
39
+
40
+ ```bash
41
+ # Initialize a new project
42
+ ev init my-app
43
+
44
+ # Inspect AST imports and compare with pyproject.toml
45
+ ev scan
46
+
47
+ # Automatically prune unused dependencies
48
+ ev prune
49
+
50
+ # Build standard wheel, sdist, and standalone zipapp
51
+ ev build --zipapp
52
+
53
+ # Run a script with in-process zero-venv dependency virtualization
54
+ ev run script.py
55
+
56
+ # Check platform reflink support and runtime info
57
+ ev info
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Programmatic Python API
63
+
64
+ Evok is built as a first-class Python library:
65
+
66
+ ```python
67
+ from evok import Environment, InMemoryProvider, Resolver
68
+
69
+ # 1. Dependency Resolution
70
+ provider = InMemoryProvider(
71
+ {
72
+ "httpx": {"0.27.0": ["httpcore>=1.0.0"]},
73
+ "httpcore": {"1.0.5": []},
74
+ }
75
+ )
76
+ resolver = Resolver(provider=provider)
77
+ graph = resolver.resolve(["httpx>=0.24.0"])
78
+ print(graph.get("httpx").version) # 0.27.0
79
+
80
+ # 2. Ephemeral Zero-Venv Execution
81
+ with Environment.ephemeral(graph) as env:
82
+ mod = env.import_module("httpx")
83
+ ```
84
+
85
+ ---
86
+
87
+ ## Documentation
88
+
89
+ - [System Architecture](docs/architecture.md)
90
+ - [CLI Reference](docs/cli.md)
91
+ - [Python API Reference](docs/api.md)
92
+ - [Performance & Bottleneck Analysis](docs/benchmarks.md)
93
+ - [Implementation Plan](IMPLEMENTATION_PLAN.md)
94
+
95
+ ---
96
+
97
+ ## License
98
+
99
+ MIT License.
@@ -0,0 +1,36 @@
1
+ [project]
2
+ name = "evok"
3
+ version = "0.1.0"
4
+ description = "Pure-Python high-performance packaging engine and virtualization runtime"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ requires-python = ">=3.12"
9
+ dependencies = []
10
+
11
+ [[project.authors]]
12
+ name = "ellainng"
13
+ email = "299958882+ellainng@users.noreply.github.com"
14
+
15
+ [project.scripts]
16
+ ev = "evok.cli:main"
17
+ evok = "evok.cli:main"
18
+
19
+ [build-system]
20
+ requires = ["uv_build>=0.13.6,<0.14.0"]
21
+ build-backend = "uv_build"
22
+
23
+ [dependency-groups]
24
+ dev = [
25
+ "pytest>=9.2.0",
26
+ "pytest-cov>=7.1.0",
27
+ "ruff>=0.17.4",
28
+ ]
29
+
30
+ [tool.ruff]
31
+ line-length = 100
32
+ target-version = "py312"
33
+
34
+ [tool.pytest.ini_options]
35
+ testpaths = ["tests"]
36
+ pythonpath = ["src"]
@@ -0,0 +1,35 @@
1
+ [project]
2
+ name = "evok"
3
+ version = "0.1.0"
4
+ description = "Pure-Python high-performance packaging engine and virtualization runtime"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ authors = [
9
+ { name = "ellainng", email = "299958882+ellainng@users.noreply.github.com" }
10
+ ]
11
+ requires-python = ">=3.12"
12
+ dependencies = []
13
+
14
+ [project.scripts]
15
+ ev = "evok.cli:main"
16
+ evok = "evok.cli:main"
17
+
18
+ [build-system]
19
+ requires = ["uv_build>=0.13.6,<0.14.0"]
20
+ build-backend = "uv_build"
21
+
22
+ [dependency-groups]
23
+ dev = [
24
+ "pytest>=9.2.0",
25
+ "pytest-cov>=7.1.0",
26
+ "ruff>=0.17.4",
27
+ ]
28
+
29
+ [tool.ruff]
30
+ line-length = 100
31
+ target-version = "py312"
32
+
33
+ [tool.pytest.ini_options]
34
+ testpaths = ["tests"]
35
+ pythonpath = ["src"]
@@ -0,0 +1,19 @@
1
+ """Evok: Pure-Python high-performance package manager and virtualization runtime."""
2
+
3
+ from evok.environment import Environment
4
+ from evok.pep440 import BitPackedVersion, SpecifierSet, VersionSpecifier
5
+ from evok.resolver import InMemoryProvider, Requirement, ResolutionGraph, Resolver
6
+
7
+ __version__ = "0.1.0"
8
+
9
+ __all__ = [
10
+ "BitPackedVersion",
11
+ "Environment",
12
+ "InMemoryProvider",
13
+ "Requirement",
14
+ "ResolutionGraph",
15
+ "Resolver",
16
+ "SpecifierSet",
17
+ "VersionSpecifier",
18
+ "__version__",
19
+ ]
@@ -0,0 +1,6 @@
1
+ from evok.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ import sys
5
+
6
+ sys.exit(main())
@@ -0,0 +1,217 @@
1
+ """AST-driven dependency inference and dead-dependency pruning.
2
+
3
+ Inspects Python AST to discover third-party imports, maps module names to PyPI distributions,
4
+ and compares against pyproject.toml to flag missing or unused dependencies.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import ast
10
+ import os
11
+ import sys
12
+ import tomllib
13
+ from dataclasses import dataclass, field
14
+ from pathlib import Path
15
+
16
+ # Known mapping of top-level import name to canonical PyPI package name
17
+ KNOWN_IMPORT_MAP: dict[str, str] = {
18
+ "yaml": "pyyaml",
19
+ "cv2": "opencv-python",
20
+ "PIL": "pillow",
21
+ "bs4": "beautifulsoup4",
22
+ "sklearn": "scikit-learn",
23
+ "dateutil": "python-dateutil",
24
+ "dotenv": "python-dotenv",
25
+ "fitz": "pymupdf",
26
+ "magic": "python-magic",
27
+ "jwt": "pyjwt",
28
+ "serial": "pyserial",
29
+ "usb": "pyusb",
30
+ "gi": "pygobject",
31
+ "git": "gitpython",
32
+ "jose": "python-jose",
33
+ "multipart": "python-multipart",
34
+ }
35
+
36
+ _IGNORED_DIRS = {
37
+ ".venv",
38
+ "venv",
39
+ ".git",
40
+ "__pycache__",
41
+ ".pytest_cache",
42
+ ".ruff_cache",
43
+ "build",
44
+ "dist",
45
+ "site-packages",
46
+ }
47
+
48
+
49
+ def get_stdlib_modules() -> set[str]:
50
+ """Return set of standard library module names."""
51
+ if hasattr(sys, "stdlib_module_names"):
52
+ return set(sys.stdlib_module_names)
53
+ # Fallback list for older or custom runtimes
54
+ return {
55
+ "os",
56
+ "sys",
57
+ "io",
58
+ "math",
59
+ "json",
60
+ "re",
61
+ "time",
62
+ "datetime",
63
+ "pathlib",
64
+ "typing",
65
+ "ast",
66
+ "unittest",
67
+ "logging",
68
+ "collections",
69
+ "urllib",
70
+ "http",
71
+ "subprocess",
72
+ "threading",
73
+ "multiprocessing",
74
+ "asyncio",
75
+ "contextlib",
76
+ "functools",
77
+ "itertools",
78
+ "shutil",
79
+ "tempfile",
80
+ "glob",
81
+ "hashlib",
82
+ "random",
83
+ "socket",
84
+ "ssl",
85
+ "inspect",
86
+ "importlib",
87
+ "ctypes",
88
+ "struct",
89
+ "copy",
90
+ "enum",
91
+ }
92
+
93
+
94
+ def normalize_package_name(name: str) -> str:
95
+ """Normalize package name according to PEP 503."""
96
+ return name.lower().replace("_", "-").replace(".", "-")
97
+
98
+
99
+ class ImportVisitor(ast.NodeVisitor):
100
+ """AST visitor collecting imported module names."""
101
+
102
+ def __init__(self) -> None:
103
+ self.imports: set[str] = set()
104
+
105
+ def visit_Import(self, node: ast.Import) -> None:
106
+ for alias in node.names:
107
+ root = alias.name.split(".")[0]
108
+ if root:
109
+ self.imports.add(root)
110
+ self.generic_visit(node)
111
+
112
+ def visit_ImportFrom(self, node: ast.ImportFrom) -> None:
113
+ if node.level == 0 and node.module:
114
+ root = node.module.split(".")[0]
115
+ if root:
116
+ self.imports.add(root)
117
+ self.generic_visit(node)
118
+
119
+
120
+ def scan_file_imports(file_path: Path | str) -> set[str]:
121
+ """Parse a single Python file and return all root imported module names."""
122
+ p = Path(file_path)
123
+ try:
124
+ content = p.read_text(encoding="utf-8", errors="ignore")
125
+ tree = ast.parse(content, filename=str(p))
126
+ except (SyntaxError, UnicodeDecodeError):
127
+ return set()
128
+
129
+ visitor = ImportVisitor()
130
+ visitor.visit(tree)
131
+ return visitor.imports
132
+
133
+
134
+ @dataclass
135
+ class ScanResult:
136
+ """Results of AST dependency scanning across a codebase."""
137
+
138
+ all_imports: set[str] = field(default_factory=set)
139
+ inferred_packages: set[str] = field(default_factory=set)
140
+ declared_dependencies: set[str] = field(default_factory=set)
141
+ missing_dependencies: set[str] = field(default_factory=set)
142
+ unused_dependencies: set[str] = field(default_factory=set)
143
+
144
+
145
+ def map_module_to_package(module_name: str) -> str:
146
+ """Map an imported module name to its likely PyPI distribution name."""
147
+ if module_name in KNOWN_IMPORT_MAP:
148
+ return KNOWN_IMPORT_MAP[module_name]
149
+ return normalize_package_name(module_name)
150
+
151
+
152
+ def scan_project(root_dir: Path | str) -> ScanResult:
153
+ """Recursively scan Python files under root_dir and audit against pyproject.toml."""
154
+ root = Path(root_dir).resolve()
155
+ stdlib = get_stdlib_modules()
156
+
157
+ # Discover local project packages/modules to avoid false positives
158
+ local_modules: set[str] = set()
159
+ for item in root.iterdir():
160
+ if item.name.startswith("."):
161
+ continue
162
+ if item.is_file() and item.suffix == ".py":
163
+ local_modules.add(item.stem)
164
+ elif item.is_dir() and (item / "__init__.py").exists():
165
+ local_modules.add(item.name)
166
+
167
+ # Check for src-layout
168
+ src_dir = root / "src"
169
+ if src_dir.is_dir():
170
+ for item in src_dir.iterdir():
171
+ if item.is_file() and item.suffix == ".py":
172
+ local_modules.add(item.stem)
173
+ elif item.is_dir() and (item / "__init__.py").exists():
174
+ local_modules.add(item.name)
175
+
176
+ all_imports: set[str] = set()
177
+ for dirpath, dirnames, filenames in os.walk(root):
178
+ dirnames[:] = [d for d in dirnames if d not in _IGNORED_DIRS and not d.startswith(".")]
179
+ for f in filenames:
180
+ if f.endswith(".py"):
181
+ file_p = Path(dirpath) / f
182
+ all_imports.update(scan_file_imports(file_p))
183
+
184
+ # Filter out stdlib and local modules
185
+ third_party_modules = {
186
+ m for m in all_imports if m not in stdlib and m not in local_modules and not m.startswith("_")
187
+ }
188
+
189
+ inferred_packages = {map_module_to_package(m) for m in third_party_modules}
190
+
191
+ # Read declared dependencies from pyproject.toml if present
192
+ declared: set[str] = set()
193
+ pyproject_file = root / "pyproject.toml"
194
+ if pyproject_file.exists():
195
+ try:
196
+ with open(pyproject_file, "rb") as f:
197
+ data = tomllib.load(f)
198
+ deps = data.get("project", {}).get("dependencies", [])
199
+ for dep in deps:
200
+ # Strip version specifiers like '>=1.0.0', '==2.0'
201
+ name = dep.split(";")[0].split(">")[0].split("<")[0].split("=")[0].split("~")[0]
202
+ name = name.strip()
203
+ if name:
204
+ declared.add(normalize_package_name(name))
205
+ except (OSError, tomllib.TOMLDecodeError):
206
+ pass
207
+
208
+ missing = inferred_packages - declared
209
+ unused = declared - inferred_packages
210
+
211
+ return ScanResult(
212
+ all_imports=all_imports,
213
+ inferred_packages=inferred_packages,
214
+ declared_dependencies=declared,
215
+ missing_dependencies=missing,
216
+ unused_dependencies=unused,
217
+ )