depvex 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.
@@ -0,0 +1,36 @@
1
+ name: Publish Python Package
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout repository
14
+ uses: actions/checkout@v4
15
+ with:
16
+ fetch-depth: 0
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v5
20
+ with:
21
+ python-version: "3.11"
22
+
23
+ - name: Upgrade pip
24
+ run: python -m pip install --upgrade pip
25
+
26
+ - name: Install build tools
27
+ run: pip install build twine setuptools_scm
28
+
29
+ - name: Build package
30
+ run: python -m build
31
+
32
+ - name: Publish to PyPI
33
+ env:
34
+ TWINE_USERNAME: __token__
35
+ TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
36
+ run: python -m twine upload --verbose dist/*
depvex-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: depvex
3
+ Version: 0.1.0
4
+ Summary: Dependency and environment checker tool
5
+ Author: Shmuel Barda
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: requests==2.34.2
9
+ Requires-Dist: typer==0.26.8
10
+ Requires-Dist: watchdog==6.0.0
depvex-0.1.0/README.md ADDED
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ import typer
2
+ from depvex.watcher import start_watching
3
+ app = typer.Typer()
4
+
5
+ @app.command()
6
+ def watch(path: str = "."):
7
+ """Watch project and auto-update requirements.txt"""
8
+ print(f"[depvex] Watching {path} ...")
9
+ start_watching(path)
10
+
11
+ def main():
12
+ app()
@@ -0,0 +1,23 @@
1
+ import ast
2
+ import sys
3
+
4
+ STD_LIB = set(getattr(sys, "stdlib_module_names", set())) | set(sys.builtin_module_names)
5
+
6
+ def extract_imports(code: str):
7
+ tree = ast.parse(code)
8
+ imports = set()
9
+
10
+ for node in ast.walk(tree):
11
+ if isinstance(node, ast.Import):
12
+ for n in node.names:
13
+ name = n.name.split(".")[0]
14
+ if name not in STD_LIB:
15
+ imports.add(name)
16
+
17
+ if isinstance(node, ast.ImportFrom):
18
+ if node.module:
19
+ name = node.module.split(".")[0]
20
+ if name not in STD_LIB:
21
+ imports.add(name)
22
+
23
+ return list(imports)
@@ -0,0 +1,155 @@
1
+ import importlib.util
2
+ import subprocess
3
+ import urllib.request
4
+ import json
5
+ import os
6
+ import requests
7
+ import time
8
+
9
+ from depvex.parser import extract_imports
10
+
11
+
12
+ CAPTIVE_PORTAL_URLS = [
13
+ "http://connectivitycheck.gstatic.com/generate_204",
14
+ "http://clients3.google.com/generate_204",
15
+ ]
16
+
17
+
18
+ # -------------------------
19
+ # Internet check
20
+ # -------------------------
21
+ def internet_check(timeout=3):
22
+ for url in CAPTIVE_PORTAL_URLS:
23
+ try:
24
+ r = requests.get(url, timeout=timeout)
25
+ if r.status_code == 204:
26
+ return True
27
+ except requests.RequestException:
28
+ pass
29
+ return False
30
+
31
+
32
+ # -------------------------
33
+ # Local / installed check
34
+ # -------------------------
35
+ def is_installed(module_name):
36
+ return importlib.util.find_spec(module_name) is not None
37
+
38
+
39
+ # -------------------------
40
+ # Get local pip version
41
+ # -------------------------
42
+ def get_local_version(module_name):
43
+ try:
44
+ result = subprocess.check_output(
45
+ ["pip", "show", module_name],
46
+ text=True
47
+ )
48
+ for line in result.splitlines():
49
+ if line.startswith("Version:"):
50
+ return line.split(":")[1].strip()
51
+ except:
52
+ return None
53
+ return None
54
+
55
+
56
+ # -------------------------
57
+ # Get PyPI version
58
+ # -------------------------
59
+ def get_pypi_version(module_name):
60
+ try:
61
+ url = f"https://pypi.org/pypi/{module_name}/json"
62
+ with urllib.request.urlopen(url, timeout=3) as r:
63
+ data = json.load(r)
64
+ return data["info"]["version"]
65
+ except:
66
+ return None
67
+
68
+
69
+ # -------------------------
70
+ # Resolve dependency
71
+ # -------------------------
72
+ def resolve(module_name, has_net):
73
+ version = get_local_version(module_name)
74
+
75
+ # installed locally → pin version
76
+ if version:
77
+ return f"{module_name}=={version}"
78
+
79
+ # not installed but internet → latest PyPI
80
+ if has_net:
81
+ v = get_pypi_version(module_name)
82
+ if v:
83
+ return f"{module_name}=={v}"
84
+ return module_name
85
+
86
+ # offline fallback
87
+ return module_name
88
+
89
+
90
+ # -------------------------
91
+ # Write requirements file
92
+ # -------------------------
93
+ def write_req(lines, path="requirements.txt"):
94
+ with open(path, "w") as f:
95
+ for l in sorted(set(lines)):
96
+ f.write(l + "\n")
97
+
98
+
99
+ # -------------------------
100
+ # Rebuild requirements from project imports
101
+ # -------------------------
102
+ def rebuild_requirements(root=".", output_path=None):
103
+ discovered = set()
104
+
105
+ for dirpath, dirnames, filenames in os.walk(root):
106
+ dirnames[:] = [d for d in dirnames if d not in {".git", "__pycache__", ".venv", "venv", "node_modules"}]
107
+
108
+ for filename in filenames:
109
+ if not filename.endswith(".py"):
110
+ continue
111
+
112
+ file_path = os.path.join(dirpath, filename)
113
+ try:
114
+ with open(file_path, "r", encoding="utf-8") as handle:
115
+ discovered.update(extract_imports(handle.read()))
116
+ except (OSError, SyntaxError):
117
+ continue
118
+
119
+ if output_path is None:
120
+ output_path = os.path.join(root, "requirements.txt")
121
+
122
+ req = []
123
+ has_net = internet_check()
124
+ for module_name in sorted(discovered):
125
+ if module_name:
126
+ req.append(resolve(module_name, has_net))
127
+
128
+ write_req(req, path=output_path)
129
+ return req
130
+
131
+
132
+ # -------------------------
133
+ # Core monitor engine
134
+ # -------------------------
135
+ def monitor_project(module_list, interval=2):
136
+ last_req = None
137
+
138
+ while True:
139
+ has_net = internet_check()
140
+
141
+ req = []
142
+
143
+ for m in module_list:
144
+ if is_installed(m):
145
+ req.append(resolve(m, has_net))
146
+
147
+ if req != last_req:
148
+ print("\n[depvex] REQUIREMENTS UPDATED")
149
+ for r in req:
150
+ print(" ", r)
151
+
152
+ write_req(req)
153
+ last_req = req
154
+
155
+ time.sleep(interval)
@@ -0,0 +1,36 @@
1
+ import time
2
+ from watchdog.observers import Observer
3
+ from watchdog.events import FileSystemEventHandler
4
+
5
+ from depvex.parser import extract_imports
6
+ from depvex.resolver import rebuild_requirements
7
+
8
+
9
+ class Handler(FileSystemEventHandler):
10
+ def __init__(self, root):
11
+ self.root = root
12
+
13
+ def on_modified(self, event):
14
+ if event.is_directory:
15
+ return
16
+
17
+ if event.src_path.endswith(".py"):
18
+ print(f"[depvex] change detected → full rescan")
19
+ rebuild_requirements(self.root)
20
+
21
+
22
+ def start_watching(path):
23
+ print("[depvex] watching:", path)
24
+
25
+ event_handler = Handler(path)
26
+ observer = Observer()
27
+ observer.schedule(event_handler, path, recursive=True)
28
+ observer.start()
29
+
30
+ try:
31
+ while True:
32
+ time.sleep(1)
33
+ except KeyboardInterrupt:
34
+ observer.stop()
35
+
36
+ observer.join()
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: depvex
3
+ Version: 0.1.0
4
+ Summary: Dependency and environment checker tool
5
+ Author: Shmuel Barda
6
+ Requires-Python: >=3.11
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: requests==2.34.2
9
+ Requires-Dist: typer==0.26.8
10
+ Requires-Dist: watchdog==6.0.0
@@ -0,0 +1,21 @@
1
+ README.md
2
+ pyproject.toml
3
+ requirements.txt
4
+ setup.py
5
+ .github/workflows/publish.yml
6
+ depvex/__init__.py
7
+ depvex/cli.py
8
+ depvex/parser.py
9
+ depvex/resolver.py
10
+ depvex/watcher.py
11
+ depvex.egg-info/PKG-INFO
12
+ depvex.egg-info/SOURCES.txt
13
+ depvex.egg-info/dependency_links.txt
14
+ depvex.egg-info/entry_points.txt
15
+ depvex.egg-info/requires.txt
16
+ depvex.egg-info/top_level.txt
17
+ depvex/__pycache__/__init__.cpython-311.pyc
18
+ depvex/__pycache__/cli.cpython-311.pyc
19
+ depvex/__pycache__/parser.cpython-311.pyc
20
+ depvex/__pycache__/resolver.cpython-311.pyc
21
+ depvex/__pycache__/watcher.cpython-311.pyc
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ depvex = depvex.cli:main
@@ -0,0 +1,3 @@
1
+ requests==2.34.2
2
+ typer==0.26.8
3
+ watchdog==6.0.0
@@ -0,0 +1 @@
1
+ depvex
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel", "setuptools_scm"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+
6
+ [project]
7
+ name = "depvex"
8
+ dynamic = ["version"]
9
+ description = "Dependency and environment checker tool"
10
+ readme = "README.md"
11
+ requires-python = ">=3.11"
12
+
13
+ authors = [
14
+ { name = "Shmuel Barda" }
15
+ ]
16
+
17
+ dependencies = [
18
+ "requests==2.34.2",
19
+ "typer==0.26.8",
20
+ "watchdog==6.0.0"
21
+ ]
22
+
23
+ [project.scripts]
24
+ depvex = "depvex.cli:main"
25
+
26
+
27
+ [tool.setuptools_scm]
28
+ version_scheme = "release-branch-semver"
29
+ local_scheme = "no-local-version"
@@ -0,0 +1,4 @@
1
+ requests==2.34.2
2
+ setuptools==81.0.0
3
+ typer==0.26.8
4
+ watchdog==6.0.0
depvex-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
depvex-0.1.0/setup.py ADDED
@@ -0,0 +1,15 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="depvex",
5
+ version="0.1.0",
6
+ packages=find_packages(),
7
+ install_requires=[
8
+ "watchdog",
9
+ ],
10
+ entry_points={
11
+ "console_scripts": [
12
+ "depvex=depvex.cli:main",
13
+ ],
14
+ },
15
+ )