nestifypy 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.
- nestifypy/__init__.py +9 -0
- nestifypy/cli.py +510 -0
- nestifypy/collections/__init__.py +21 -0
- nestifypy/collections/array_list.py +270 -0
- nestifypy/collections/hash_map.py +285 -0
- nestifypy/collections/linked_list.py +222 -0
- nestifypy/collections/ordered_set.py +183 -0
- nestifypy/collections/queue.py +147 -0
- nestifypy/collections/stack.py +148 -0
- nestifypy/console/__init__.py +329 -0
- nestifypy/core/__init__.py +287 -0
- nestifypy/decorators/__init__.py +675 -0
- nestifypy/env/__init__.py +189 -0
- nestifypy/flow/__init__.py +319 -0
- nestifypy/json/__init__.py +18 -0
- nestifypy/json/engine.py +88 -0
- nestifypy/json/exceptions.py +19 -0
- nestifypy/json/models.py +13 -0
- nestifypy/json/parser.py +45 -0
- nestifypy/json/serializer.py +39 -0
- nestifypy/json/utils.py +25 -0
- nestifypy/json/validator.py +45 -0
- nestifypy/os/__init__.py +13 -0
- nestifypy/os/dirs.py +61 -0
- nestifypy/os/files.py +80 -0
- nestifypy/os/paths.py +43 -0
- nestifypy/os/process.py +56 -0
- nestifypy/os/system.py +50 -0
- nestifypy/py.typed +1 -0
- nestifypy/pyunix/__init__.py +55 -0
- nestifypy/pyunix/app.py +404 -0
- nestifypy/pyunix/assets.py +241 -0
- nestifypy/pyunix/audio.py +128 -0
- nestifypy/pyunix/camera.py +135 -0
- nestifypy/pyunix/events.py +108 -0
- nestifypy/pyunix/exceptions.py +35 -0
- nestifypy/pyunix/fonts.py +71 -0
- nestifypy/pyunix/input.py +271 -0
- nestifypy/pyunix/physics.py +363 -0
- nestifypy/pyunix/scene.py +277 -0
- nestifypy/pyunix/sprite.py +350 -0
- nestifypy/pyunix/text.py +148 -0
- nestifypy/pyunix/timer.py +149 -0
- nestifypy/pyunix/window.py +136 -0
- nestifypy/types/__init__.py +239 -0
- nestifypy/utils/__init__.py +206 -0
- nestifypy/version.py +1 -0
- nestifypy/yaml/__init__.py +91 -0
- nestifypy/yaml/bootstrap.py +28 -0
- nestifypy/yaml/cache.py +36 -0
- nestifypy/yaml/engine.py +239 -0
- nestifypy/yaml/exceptions.py +11 -0
- nestifypy/yaml/metadata.py +88 -0
- nestifypy/yaml/models.py +79 -0
- nestifypy/yaml/proxy.py +50 -0
- nestifypy/yaml/registry.py +84 -0
- nestifypy/yaml/runtime.py +92 -0
- nestifypy/yaml/scanner.py +107 -0
- nestifypy/yaml/watcher.py +117 -0
- nestifypy-0.1.0.dist-info/METADATA +208 -0
- nestifypy-0.1.0.dist-info/RECORD +65 -0
- nestifypy-0.1.0.dist-info/WHEEL +5 -0
- nestifypy-0.1.0.dist-info/entry_points.txt +2 -0
- nestifypy-0.1.0.dist-info/licenses/LICENSE +21 -0
- nestifypy-0.1.0.dist-info/top_level.txt +1 -0
nestifypy/__init__.py
ADDED
nestifypy/cli.py
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
"""
|
|
2
|
+
nestifypy.cli
|
|
3
|
+
----------
|
|
4
|
+
CLI entry point for the Nestifypy ecosystem.
|
|
5
|
+
Registered via pyproject.toml: nestifypy = "nestifypy.cli:main"
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import re
|
|
11
|
+
import sys
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import Optional
|
|
14
|
+
|
|
15
|
+
import typer
|
|
16
|
+
|
|
17
|
+
app = typer.Typer(
|
|
18
|
+
name="nestifypy",
|
|
19
|
+
help="Nestifypy — Modern utility and game framework for Python",
|
|
20
|
+
no_args_is_help=True,
|
|
21
|
+
rich_markup_mode="rich",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
+
# Default project.yml template
|
|
26
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
_DEFAULT_PROJECT_YML = """\
|
|
29
|
+
project:
|
|
30
|
+
name: "{name}"
|
|
31
|
+
version: "0.1.0"
|
|
32
|
+
description: ""
|
|
33
|
+
|
|
34
|
+
python:
|
|
35
|
+
version: "{python_version}"
|
|
36
|
+
|
|
37
|
+
build:
|
|
38
|
+
backend: "uv"
|
|
39
|
+
|
|
40
|
+
docker:
|
|
41
|
+
image: "{name}:latest"
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
_DEFAULT_PYPROJECT = """\
|
|
45
|
+
[build-system]
|
|
46
|
+
requires = ["setuptools>=69", "wheel"]
|
|
47
|
+
build-backend = "setuptools.build_meta"
|
|
48
|
+
|
|
49
|
+
[project]
|
|
50
|
+
name = "{name}"
|
|
51
|
+
version = "0.1.0"
|
|
52
|
+
description = ""
|
|
53
|
+
requires-python = ">={python_version}"
|
|
54
|
+
dependencies = [
|
|
55
|
+
"nestifypy>=0.1.0"
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[project.optional-dependencies]
|
|
59
|
+
dev = [
|
|
60
|
+
"ruff>=0.4",
|
|
61
|
+
"pytest>=8.0",
|
|
62
|
+
"mypy>=1.10"
|
|
63
|
+
]
|
|
64
|
+
|
|
65
|
+
[project.scripts]
|
|
66
|
+
{name} = "{name}.cli:main"
|
|
67
|
+
|
|
68
|
+
[tool.ruff]
|
|
69
|
+
line-length = 88
|
|
70
|
+
target-version = "py310"
|
|
71
|
+
|
|
72
|
+
[tool.ruff.lint]
|
|
73
|
+
select = ["E", "F", "I", "N", "W", "UP"]
|
|
74
|
+
|
|
75
|
+
[tool.pytest.ini_options]
|
|
76
|
+
testpaths = ["tests"]
|
|
77
|
+
python_files = ["test_*.py"]
|
|
78
|
+
addopts = "-v"
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
_DEFAULT_GITIGNORE = """\
|
|
82
|
+
# Byte-compiled / optimized / DLL files
|
|
83
|
+
__pycache__/
|
|
84
|
+
*.py[cod]
|
|
85
|
+
*$py.class
|
|
86
|
+
|
|
87
|
+
# C extensions
|
|
88
|
+
*.so
|
|
89
|
+
|
|
90
|
+
# Distribution / packaging
|
|
91
|
+
.Python
|
|
92
|
+
build/
|
|
93
|
+
develop-eggs/
|
|
94
|
+
dist/
|
|
95
|
+
downloads/
|
|
96
|
+
eggs/
|
|
97
|
+
.eggs/
|
|
98
|
+
lib/
|
|
99
|
+
lib64/
|
|
100
|
+
parts/
|
|
101
|
+
sdist/
|
|
102
|
+
var/
|
|
103
|
+
wheels/
|
|
104
|
+
share/python-wheels/
|
|
105
|
+
*.egg-info/
|
|
106
|
+
.installed.cfg
|
|
107
|
+
*.egg
|
|
108
|
+
MANIFEST
|
|
109
|
+
|
|
110
|
+
# PyInstaller
|
|
111
|
+
# Usually these files are written by a python script from a template
|
|
112
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
113
|
+
*.manifest
|
|
114
|
+
*.spec
|
|
115
|
+
|
|
116
|
+
# Installer logs
|
|
117
|
+
pip-log.txt
|
|
118
|
+
pip-delete-this-directory.txt
|
|
119
|
+
|
|
120
|
+
# Unit test / coverage reports
|
|
121
|
+
htmlcov/
|
|
122
|
+
.tox/
|
|
123
|
+
.nox/
|
|
124
|
+
.coverage
|
|
125
|
+
.coverage.*
|
|
126
|
+
.cache
|
|
127
|
+
nosetests.xml
|
|
128
|
+
coverage.xml
|
|
129
|
+
*.cover
|
|
130
|
+
*.py,cover
|
|
131
|
+
.hypothesis/
|
|
132
|
+
.pytest_cache/
|
|
133
|
+
cover/
|
|
134
|
+
|
|
135
|
+
# Translations
|
|
136
|
+
*.mo
|
|
137
|
+
*.pot
|
|
138
|
+
|
|
139
|
+
# Django stuff:
|
|
140
|
+
*.log
|
|
141
|
+
local_settings.py
|
|
142
|
+
db.sqlite3
|
|
143
|
+
db.sqlite3-journal
|
|
144
|
+
|
|
145
|
+
# Flask stuff:
|
|
146
|
+
instance/
|
|
147
|
+
.webassets-cache
|
|
148
|
+
|
|
149
|
+
# Scrapy stuff:
|
|
150
|
+
.scrapy
|
|
151
|
+
|
|
152
|
+
# Sphinx documentation
|
|
153
|
+
docs/_build/
|
|
154
|
+
|
|
155
|
+
# PyBuilder
|
|
156
|
+
.pybuilder/
|
|
157
|
+
target/
|
|
158
|
+
|
|
159
|
+
# Jupyter Notebook
|
|
160
|
+
.ipynb_checkpoints
|
|
161
|
+
|
|
162
|
+
# IPython
|
|
163
|
+
profile_default/
|
|
164
|
+
ipython_config.py
|
|
165
|
+
|
|
166
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
|
167
|
+
__pypackages__/
|
|
168
|
+
|
|
169
|
+
# Celery stuff
|
|
170
|
+
celerybeat-schedule
|
|
171
|
+
celerybeat.pid
|
|
172
|
+
|
|
173
|
+
# SageMath parsed files
|
|
174
|
+
*.sage.py
|
|
175
|
+
|
|
176
|
+
# Environments
|
|
177
|
+
.env
|
|
178
|
+
.venv
|
|
179
|
+
env/
|
|
180
|
+
venv/
|
|
181
|
+
ENV/
|
|
182
|
+
env.bak/
|
|
183
|
+
venv.bak/
|
|
184
|
+
|
|
185
|
+
# Spyder project settings
|
|
186
|
+
.spyderproject
|
|
187
|
+
.spyproject
|
|
188
|
+
|
|
189
|
+
# Rope project settings
|
|
190
|
+
.ropeproject
|
|
191
|
+
|
|
192
|
+
# mkdocs documentation
|
|
193
|
+
/site
|
|
194
|
+
|
|
195
|
+
# mypy
|
|
196
|
+
.mypy_cache/
|
|
197
|
+
.dmypy.json
|
|
198
|
+
dmypy.json
|
|
199
|
+
|
|
200
|
+
# Pyre type checker
|
|
201
|
+
.pyre/
|
|
202
|
+
|
|
203
|
+
# pytype static type analyzer
|
|
204
|
+
.pytype/
|
|
205
|
+
|
|
206
|
+
# Cython debug symbols
|
|
207
|
+
cython_debug/
|
|
208
|
+
|
|
209
|
+
# IDEs / Editors
|
|
210
|
+
.idea/
|
|
211
|
+
.vscode/
|
|
212
|
+
*.swp
|
|
213
|
+
*.swo
|
|
214
|
+
*~
|
|
215
|
+
.DS_Store
|
|
216
|
+
|
|
217
|
+
# PyNest specific / local files
|
|
218
|
+
.nestifypy/
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
_DEFAULT_MAIN = """\
|
|
222
|
+
from nestifypy.core import Logger
|
|
223
|
+
from nestifypy.env import Env
|
|
224
|
+
|
|
225
|
+
def main() -> None:
|
|
226
|
+
Env.load()
|
|
227
|
+
Logger.info("Hello from {name}! Environment loaded successfully.")
|
|
228
|
+
|
|
229
|
+
if __name__ == "__main__":
|
|
230
|
+
main()
|
|
231
|
+
"""
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
235
|
+
# init
|
|
236
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
237
|
+
|
|
238
|
+
@app.command()
|
|
239
|
+
def init(
|
|
240
|
+
name: Optional[str] = typer.Option(
|
|
241
|
+
None, "--name", "-n", help="Project name"
|
|
242
|
+
),
|
|
243
|
+
python: str = typer.Option(
|
|
244
|
+
"3.11", "--python", "-p", help="Python version"
|
|
245
|
+
),
|
|
246
|
+
force: bool = typer.Option(
|
|
247
|
+
False, "--force", "-f", help="Overwrite existing files"
|
|
248
|
+
),
|
|
249
|
+
) -> None:
|
|
250
|
+
"""Initialize a new Nestifypy project in the current directory."""
|
|
251
|
+
|
|
252
|
+
# Resolve project name
|
|
253
|
+
if name is None:
|
|
254
|
+
name = Path.cwd().name
|
|
255
|
+
|
|
256
|
+
typer.echo(f"\n🪺 Initializing Nestifypy project: [bold]{name}[/bold]\n", color=True)
|
|
257
|
+
|
|
258
|
+
files = {
|
|
259
|
+
"project.yml": _DEFAULT_PROJECT_YML.format(name=name, python_version=python),
|
|
260
|
+
"pyproject.toml": _DEFAULT_PYPROJECT.format(name=name, python_version=python),
|
|
261
|
+
".gitignore": _DEFAULT_GITIGNORE,
|
|
262
|
+
".python-version": python,
|
|
263
|
+
f"src/{name}/__init__.py": "",
|
|
264
|
+
f"src/{name}/main.py": _DEFAULT_MAIN.format(name=name),
|
|
265
|
+
"tests/__init__.py": "",
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
created = []
|
|
269
|
+
skipped = []
|
|
270
|
+
|
|
271
|
+
for filepath, content in files.items():
|
|
272
|
+
p = Path(filepath)
|
|
273
|
+
if p.exists() and not force:
|
|
274
|
+
skipped.append(filepath)
|
|
275
|
+
continue
|
|
276
|
+
p.parent.mkdir(parents=True, exist_ok=True)
|
|
277
|
+
p.write_text(content, encoding="utf-8")
|
|
278
|
+
created.append(filepath)
|
|
279
|
+
|
|
280
|
+
for f in created:
|
|
281
|
+
typer.echo(f" ✓ created {f}")
|
|
282
|
+
for f in skipped:
|
|
283
|
+
typer.echo(f" – skipped {f} (use --force to overwrite)")
|
|
284
|
+
|
|
285
|
+
typer.echo(f"\n✅ Project [bold]{name}[/bold] ready!\n")
|
|
286
|
+
typer.echo(" Next steps:")
|
|
287
|
+
typer.echo(" uv sync")
|
|
288
|
+
typer.echo(" nestifypy run\n")
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
292
|
+
# sync
|
|
293
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
294
|
+
|
|
295
|
+
@app.command()
|
|
296
|
+
def sync(
|
|
297
|
+
config: str = typer.Option("project.yml", "--config", "-c", help="Config file"),
|
|
298
|
+
) -> None:
|
|
299
|
+
"""Sync pyproject.toml, .python-version, and Docker files from project.yml."""
|
|
300
|
+
|
|
301
|
+
try:
|
|
302
|
+
import yaml
|
|
303
|
+
except ImportError:
|
|
304
|
+
typer.echo("❌ pyyaml not installed. Run: pip install pyyaml")
|
|
305
|
+
raise typer.Exit(1)
|
|
306
|
+
|
|
307
|
+
cfg_path = Path(config)
|
|
308
|
+
if not cfg_path.exists():
|
|
309
|
+
typer.echo(f"❌ Config file not found: {config}")
|
|
310
|
+
raise typer.Exit(1)
|
|
311
|
+
|
|
312
|
+
with open(cfg_path, "r") as f:
|
|
313
|
+
cfg = yaml.safe_load(f)
|
|
314
|
+
|
|
315
|
+
python_version: str = str(cfg.get("python", {}).get("version", "3.11"))
|
|
316
|
+
project_name: str = cfg.get("project", {}).get("name", "project")
|
|
317
|
+
project_version: str = cfg.get("project", {}).get("version", "0.1.0")
|
|
318
|
+
|
|
319
|
+
typer.echo(f"\n🔄 Syncing from {config}…\n")
|
|
320
|
+
|
|
321
|
+
# .python-version
|
|
322
|
+
pv_path = Path(".python-version")
|
|
323
|
+
pv_path.write_text(python_version)
|
|
324
|
+
typer.echo(f" ✓ .python-version → {python_version}")
|
|
325
|
+
|
|
326
|
+
# pyproject.toml
|
|
327
|
+
pp_path = Path("pyproject.toml")
|
|
328
|
+
if pp_path.exists():
|
|
329
|
+
content = pp_path.read_text(encoding="utf-8")
|
|
330
|
+
content = re.sub(
|
|
331
|
+
r'requires-python\s*=\s*"[^"]+"',
|
|
332
|
+
f'requires-python = ">={python_version}"',
|
|
333
|
+
content,
|
|
334
|
+
)
|
|
335
|
+
content = re.sub(
|
|
336
|
+
r'^version\s*=\s*"[^"]+"',
|
|
337
|
+
f'version = "{project_version}"',
|
|
338
|
+
content,
|
|
339
|
+
flags=re.MULTILINE,
|
|
340
|
+
)
|
|
341
|
+
pp_path.write_text(content, encoding="utf-8")
|
|
342
|
+
typer.echo(f" ✓ pyproject.toml → version={project_version}, python>={python_version}")
|
|
343
|
+
|
|
344
|
+
typer.echo(f"\n✅ Sync complete.\n")
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
348
|
+
# run
|
|
349
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
350
|
+
|
|
351
|
+
@app.command()
|
|
352
|
+
def run(
|
|
353
|
+
entry: str = typer.Option("main.py", "--entry", "-e", help="Entry file to run"),
|
|
354
|
+
module: Optional[str] = typer.Option(None, "--module", "-m", help="Module to run"),
|
|
355
|
+
) -> None:
|
|
356
|
+
"""Run the project entry point."""
|
|
357
|
+
import subprocess
|
|
358
|
+
|
|
359
|
+
if module:
|
|
360
|
+
typer.echo(f"\n▶ Running module: {module}\n")
|
|
361
|
+
subprocess.run([sys.executable, "-m", module], check=False)
|
|
362
|
+
else:
|
|
363
|
+
entry_path = Path(entry)
|
|
364
|
+
if not entry_path.exists():
|
|
365
|
+
# Try src/<name>/main.py
|
|
366
|
+
candidates = list(Path("src").rglob("main.py")) if Path("src").exists() else []
|
|
367
|
+
if candidates:
|
|
368
|
+
entry_path = candidates[0]
|
|
369
|
+
else:
|
|
370
|
+
typer.echo(f"❌ Entry file not found: {entry}")
|
|
371
|
+
raise typer.Exit(1)
|
|
372
|
+
typer.echo(f"\n▶ Running: {entry_path}\n")
|
|
373
|
+
subprocess.run([sys.executable, str(entry_path)], check=False)
|
|
374
|
+
|
|
375
|
+
|
|
376
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
377
|
+
# build
|
|
378
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
379
|
+
|
|
380
|
+
@app.command()
|
|
381
|
+
def build(
|
|
382
|
+
output: str = typer.Option("dist/", "--output", "-o", help="Output directory"),
|
|
383
|
+
) -> None:
|
|
384
|
+
"""Build the project distribution."""
|
|
385
|
+
import subprocess
|
|
386
|
+
|
|
387
|
+
typer.echo(f"\n📦 Building project…\n")
|
|
388
|
+
result = subprocess.run(
|
|
389
|
+
[sys.executable, "-m", "build", "--outdir", output],
|
|
390
|
+
capture_output=False,
|
|
391
|
+
)
|
|
392
|
+
if result.returncode == 0:
|
|
393
|
+
typer.echo(f"\n✅ Build complete → {output}\n")
|
|
394
|
+
else:
|
|
395
|
+
typer.echo("\n❌ Build failed.\n")
|
|
396
|
+
raise typer.Exit(result.returncode)
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
400
|
+
# doctor
|
|
401
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
402
|
+
|
|
403
|
+
@app.command()
|
|
404
|
+
def doctor() -> None:
|
|
405
|
+
"""Check environment health and installed dependencies."""
|
|
406
|
+
import importlib
|
|
407
|
+
import platform
|
|
408
|
+
|
|
409
|
+
typer.echo("\n🩺 Nestifypy Doctor\n")
|
|
410
|
+
|
|
411
|
+
typer.echo(f" Python : {platform.python_version()}")
|
|
412
|
+
typer.echo(f" Platform : {platform.system()} {platform.machine()}")
|
|
413
|
+
typer.echo(f" Executable : {sys.executable}\n")
|
|
414
|
+
|
|
415
|
+
deps = [
|
|
416
|
+
("pyyaml", "yaml"),
|
|
417
|
+
("python-dotenv","dotenv"),
|
|
418
|
+
("typer", "typer"),
|
|
419
|
+
("watchdog", "watchdog"),
|
|
420
|
+
("pygame", "pygame"),
|
|
421
|
+
("ruff", "ruff"),
|
|
422
|
+
("pytest", "pytest"),
|
|
423
|
+
("mypy", "mypy"),
|
|
424
|
+
]
|
|
425
|
+
|
|
426
|
+
for display_name, import_name in deps:
|
|
427
|
+
try:
|
|
428
|
+
mod = importlib.import_module(import_name)
|
|
429
|
+
version = getattr(mod, "__version__", "?")
|
|
430
|
+
typer.echo(f" ✓ {display_name:<20} {version}")
|
|
431
|
+
except ImportError:
|
|
432
|
+
typer.echo(f" – {display_name:<20} not installed")
|
|
433
|
+
|
|
434
|
+
# Check project.yml
|
|
435
|
+
typer.echo()
|
|
436
|
+
if Path("project.yml").exists():
|
|
437
|
+
typer.echo(" ✓ project.yml found")
|
|
438
|
+
else:
|
|
439
|
+
typer.echo(" – project.yml not found (run: nestifypy init)")
|
|
440
|
+
|
|
441
|
+
typer.echo()
|
|
442
|
+
|
|
443
|
+
|
|
444
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
445
|
+
# clean
|
|
446
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
447
|
+
|
|
448
|
+
@app.command()
|
|
449
|
+
def clean() -> None:
|
|
450
|
+
"""Remove build artifacts and caches."""
|
|
451
|
+
import shutil
|
|
452
|
+
|
|
453
|
+
targets = [
|
|
454
|
+
"dist", "build", ".nestifypy",
|
|
455
|
+
"__pycache__", ".mypy_cache", ".ruff_cache",
|
|
456
|
+
]
|
|
457
|
+
removed = []
|
|
458
|
+
for target in targets:
|
|
459
|
+
for p in Path(".").rglob(target):
|
|
460
|
+
if p.is_dir():
|
|
461
|
+
shutil.rmtree(p)
|
|
462
|
+
removed.append(str(p))
|
|
463
|
+
|
|
464
|
+
if removed:
|
|
465
|
+
for r in removed:
|
|
466
|
+
typer.echo(f" 🗑 removed {r}")
|
|
467
|
+
typer.echo(f"\n✅ Cleaned {len(removed)} items.\n")
|
|
468
|
+
else:
|
|
469
|
+
typer.echo(" Nothing to clean.")
|
|
470
|
+
|
|
471
|
+
|
|
472
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
473
|
+
# info
|
|
474
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
475
|
+
|
|
476
|
+
@app.command()
|
|
477
|
+
def info() -> None:
|
|
478
|
+
"""Show project info from project.yml."""
|
|
479
|
+
try:
|
|
480
|
+
import yaml
|
|
481
|
+
cfg_path = Path("project.yml")
|
|
482
|
+
if not cfg_path.exists():
|
|
483
|
+
typer.echo("❌ project.yml not found. Run: nestifypy init")
|
|
484
|
+
raise typer.Exit(1)
|
|
485
|
+
with open(cfg_path) as f:
|
|
486
|
+
cfg = yaml.safe_load(f)
|
|
487
|
+
|
|
488
|
+
typer.echo("\n🪺 Nestifypy Project Info\n")
|
|
489
|
+
proj = cfg.get("project", {})
|
|
490
|
+
typer.echo(f" Name : {proj.get('name', '-')}")
|
|
491
|
+
typer.echo(f" Version : {proj.get('version', '-')}")
|
|
492
|
+
typer.echo(f" Description : {proj.get('description', '-')}")
|
|
493
|
+
typer.echo(f" Python : {cfg.get('python', {}).get('version', '-')}")
|
|
494
|
+
typer.echo(f" Build : {cfg.get('build', {}).get('backend', '-')}")
|
|
495
|
+
typer.echo()
|
|
496
|
+
except ImportError:
|
|
497
|
+
typer.echo("❌ pyyaml required: pip install pyyaml")
|
|
498
|
+
raise typer.Exit(1)
|
|
499
|
+
|
|
500
|
+
|
|
501
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
502
|
+
# Entry
|
|
503
|
+
# ─────────────────────────────────────────────────────────────────────────────
|
|
504
|
+
|
|
505
|
+
def main() -> None:
|
|
506
|
+
app()
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
if __name__ == "__main__":
|
|
510
|
+
main()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""
|
|
2
|
+
nestifypy.collections
|
|
3
|
+
------------------
|
|
4
|
+
Fluent, Java-inspired data structures.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from nestifypy.collections.array_list import ArrayList
|
|
8
|
+
from nestifypy.collections.linked_list import LinkedList
|
|
9
|
+
from nestifypy.collections.stack import Stack
|
|
10
|
+
from nestifypy.collections.queue import Queue
|
|
11
|
+
from nestifypy.collections.ordered_set import OrderedSet
|
|
12
|
+
from nestifypy.collections.hash_map import HashMap
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"ArrayList",
|
|
16
|
+
"LinkedList",
|
|
17
|
+
"Stack",
|
|
18
|
+
"Queue",
|
|
19
|
+
"OrderedSet",
|
|
20
|
+
"HashMap",
|
|
21
|
+
]
|