apcore-cli 0.4.1__tar.gz → 0.5.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.
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/PKG-INFO +2 -2
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/pyproject.toml +2 -2
- apcore_cli-0.5.0/src/apcore_cli/__init__.py +27 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/__main__.py +4 -1
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/cli.py +14 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/config.py +21 -3
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/shell.py +45 -1
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_config.py +44 -0
- apcore_cli-0.4.1/src/apcore_cli/__init__.py +0 -9
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/.github/CODEOWNERS +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/.github/copilot-ignore +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/.github/workflows/ci.yml +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/.gitignore +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/.gitmessage +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/.pre-commit-config.yaml +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/CHANGELOG.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/CLAUDE.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/README.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/commands/ops.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/math/add.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/math/multiply.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/sysutil/disk.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/sysutil/env.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/sysutil/info.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/text/reverse.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/text/upper.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/extensions/text/wordcount.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/examples/run_examples.sh +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/approval-gate.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/config-resolver.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/core-dispatcher.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/discovery.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/grouped-commands.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/output-formatter.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/overview.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/schema-parser.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/security-manager.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/shell-integration.md +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/planning/state.json +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/_sandbox_runner.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/approval.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/discovery.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/display_helpers.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/init_cmd.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/output.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/ref_resolver.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/schema_parser.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/security/__init__.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/security/audit.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/security/auth.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/security/config_encryptor.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/src/apcore_cli/security/sandbox.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/__init__.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/conftest.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_approval.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_bugfixes.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_cli.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_discovery.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_e2e.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_init_cmd.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_integration.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_output.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_ref_resolver.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_schema_parser.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_security/__init__.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_security/test_audit.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_security/test_auth.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_security/test_config_encryptor.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_security/test_sandbox.py +0 -0
- {apcore_cli-0.4.1 → apcore_cli-0.5.0}/tests/test_shell.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: apcore-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Terminal adapter for apcore — execute AI-Perceivable modules from the command line
|
|
5
5
|
Project-URL: Homepage, https://aiperceivable.com
|
|
6
6
|
Project-URL: Repository, https://github.com/aiperceivable/apcore-cli-python
|
|
@@ -20,7 +20,7 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
20
20
|
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
21
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
22
|
Requires-Python: >=3.11
|
|
23
|
-
Requires-Dist: apcore>=0.
|
|
23
|
+
Requires-Dist: apcore>=0.15.1
|
|
24
24
|
Requires-Dist: click>=8.1
|
|
25
25
|
Requires-Dist: cryptography>=41.0
|
|
26
26
|
Requires-Dist: jsonschema>=4.20
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "apcore-cli"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "Terminal adapter for apcore — execute AI-Perceivable modules from the command line"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
@@ -26,7 +26,7 @@ classifiers = [
|
|
|
26
26
|
"Environment :: Console",
|
|
27
27
|
]
|
|
28
28
|
dependencies = [
|
|
29
|
-
"apcore>=0.
|
|
29
|
+
"apcore>=0.15.1",
|
|
30
30
|
"click>=8.1",
|
|
31
31
|
"jsonschema>=4.20",
|
|
32
32
|
"rich>=13.0",
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""apcore-cli: CLI adapter for the apcore module ecosystem."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError
|
|
4
|
+
from importlib.metadata import version as _get_version
|
|
5
|
+
|
|
6
|
+
try:
|
|
7
|
+
__version__ = _get_version("apcore-cli")
|
|
8
|
+
except PackageNotFoundError:
|
|
9
|
+
__version__ = "unknown"
|
|
10
|
+
|
|
11
|
+
# Config Bus namespace registration (apcore >= 0.15.0)
|
|
12
|
+
try:
|
|
13
|
+
from apcore import Config
|
|
14
|
+
|
|
15
|
+
Config.register_namespace(
|
|
16
|
+
name="apcore-cli",
|
|
17
|
+
schema=None,
|
|
18
|
+
env_prefix="APCORE_CLI",
|
|
19
|
+
defaults={
|
|
20
|
+
"stdin_buffer_limit": 10_485_760,
|
|
21
|
+
"auto_approve": False,
|
|
22
|
+
"help_text_max_length": 1000,
|
|
23
|
+
"logging_level": "WARNING",
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
except (ImportError, AttributeError):
|
|
27
|
+
pass # apcore < 0.15.0 or not installed
|
|
@@ -13,7 +13,7 @@ from apcore_cli.cli import GroupedModuleGroup, set_audit_logger, set_verbose_hel
|
|
|
13
13
|
from apcore_cli.config import ConfigResolver
|
|
14
14
|
from apcore_cli.discovery import register_discovery_commands
|
|
15
15
|
from apcore_cli.security.audit import AuditLogger
|
|
16
|
-
from apcore_cli.shell import register_shell_commands
|
|
16
|
+
from apcore_cli.shell import configure_man_help, register_shell_commands
|
|
17
17
|
|
|
18
18
|
logger = logging.getLogger("apcore_cli")
|
|
19
19
|
|
|
@@ -256,6 +256,9 @@ def create_cli(
|
|
|
256
256
|
# Register shell integration commands
|
|
257
257
|
register_shell_commands(cli, prog_name=prog_name)
|
|
258
258
|
|
|
259
|
+
# Register --help --man support
|
|
260
|
+
configure_man_help(cli, prog_name, __version__)
|
|
261
|
+
|
|
259
262
|
# Register init scaffolding command
|
|
260
263
|
from apcore_cli.init_cmd import register_init_command
|
|
261
264
|
|
|
@@ -343,6 +343,13 @@ class GroupedModuleGroup(LazyModuleGroup):
|
|
|
343
343
|
with formatter.section("Groups"):
|
|
344
344
|
formatter.write_dl(group_records)
|
|
345
345
|
|
|
346
|
+
# Footer hints for discoverability
|
|
347
|
+
formatter.write_paragraph()
|
|
348
|
+
formatter.write(
|
|
349
|
+
"Use --help --verbose to show all options (including built-in apcore options).\n"
|
|
350
|
+
"Use --help --man to display a formatted man page."
|
|
351
|
+
)
|
|
352
|
+
|
|
346
353
|
|
|
347
354
|
# Error code mapping from apcore error codes to CLI exit codes
|
|
348
355
|
_ERROR_CODE_MAP = {
|
|
@@ -359,6 +366,13 @@ _ERROR_CODE_MAP = {
|
|
|
359
366
|
"MODULE_EXECUTE_ERROR": 1,
|
|
360
367
|
"MODULE_TIMEOUT": 1,
|
|
361
368
|
"ACL_DENIED": 77,
|
|
369
|
+
# Config Bus errors (apcore >= 0.15.0)
|
|
370
|
+
"CONFIG_NAMESPACE_RESERVED": 78,
|
|
371
|
+
"CONFIG_NAMESPACE_DUPLICATE": 78,
|
|
372
|
+
"CONFIG_ENV_PREFIX_CONFLICT": 78,
|
|
373
|
+
"CONFIG_MOUNT_ERROR": 66,
|
|
374
|
+
"CONFIG_BIND_ERROR": 65,
|
|
375
|
+
"ERROR_FORMATTER_DUPLICATE": 70,
|
|
362
376
|
}
|
|
363
377
|
|
|
364
378
|
|
|
@@ -16,6 +16,15 @@ class ConfigResolver:
|
|
|
16
16
|
CLI flag > Environment variable > Config file > Default.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
|
+
# Namespace key -> legacy key mapping for backward compatibility
|
|
20
|
+
_NAMESPACE_TO_LEGACY: dict[str, str] = {
|
|
21
|
+
"apcore-cli.stdin_buffer_limit": "cli.stdin_buffer_limit",
|
|
22
|
+
"apcore-cli.auto_approve": "cli.auto_approve",
|
|
23
|
+
"apcore-cli.help_text_max_length": "cli.help_text_max_length",
|
|
24
|
+
"apcore-cli.logging_level": "logging.level",
|
|
25
|
+
}
|
|
26
|
+
_LEGACY_TO_NAMESPACE: dict[str, str] = {v: k for k, v in _NAMESPACE_TO_LEGACY.items()}
|
|
27
|
+
|
|
19
28
|
DEFAULTS: dict[str, Any] = {
|
|
20
29
|
"extensions.root": "./extensions",
|
|
21
30
|
"logging.level": "WARNING",
|
|
@@ -23,6 +32,11 @@ class ConfigResolver:
|
|
|
23
32
|
"cli.stdin_buffer_limit": 10_485_760, # 10 MB
|
|
24
33
|
"cli.auto_approve": False,
|
|
25
34
|
"cli.help_text_max_length": 1000,
|
|
35
|
+
# Namespace-mode aliases (apcore >= 0.15.0 Config Bus)
|
|
36
|
+
"apcore-cli.stdin_buffer_limit": 10_485_760,
|
|
37
|
+
"apcore-cli.auto_approve": False,
|
|
38
|
+
"apcore-cli.help_text_max_length": 1000,
|
|
39
|
+
"apcore-cli.logging_level": "WARNING",
|
|
26
40
|
}
|
|
27
41
|
|
|
28
42
|
def __init__(
|
|
@@ -53,9 +67,13 @@ class ConfigResolver:
|
|
|
53
67
|
if env_value is not None and env_value != "":
|
|
54
68
|
return env_value
|
|
55
69
|
|
|
56
|
-
# Tier 3: Config file
|
|
57
|
-
if self._config_file is not None
|
|
58
|
-
|
|
70
|
+
# Tier 3: Config file (try both namespace and legacy keys)
|
|
71
|
+
if self._config_file is not None:
|
|
72
|
+
if key in self._config_file:
|
|
73
|
+
return self._config_file[key]
|
|
74
|
+
alt_key = self._NAMESPACE_TO_LEGACY.get(key) or self._LEGACY_TO_NAMESPACE.get(key)
|
|
75
|
+
if alt_key and alt_key in self._config_file:
|
|
76
|
+
return self._config_file[alt_key]
|
|
59
77
|
|
|
60
78
|
# Tier 4: Default
|
|
61
79
|
return self.DEFAULTS.get(key)
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import os
|
|
5
6
|
import re
|
|
6
7
|
import shlex
|
|
8
|
+
import subprocess
|
|
7
9
|
import sys
|
|
8
10
|
from datetime import date
|
|
9
11
|
|
|
@@ -480,6 +482,48 @@ def build_program_man_page(
|
|
|
480
482
|
return "\n".join(s)
|
|
481
483
|
|
|
482
484
|
|
|
485
|
+
def _render_man_page(roff: str) -> None:
|
|
486
|
+
"""Render a roff man page to stdout.
|
|
487
|
+
|
|
488
|
+
When stdout is a TTY, attempts to render through mandoc or groff and
|
|
489
|
+
pipe through a pager for formatted display. When stdout is not a TTY
|
|
490
|
+
(piped or redirected), outputs raw roff for file redirection.
|
|
491
|
+
"""
|
|
492
|
+
roff_bytes = roff.encode()
|
|
493
|
+
if not sys.stdout.isatty():
|
|
494
|
+
sys.stdout.write(roff)
|
|
495
|
+
return
|
|
496
|
+
|
|
497
|
+
# Try mandoc first (macOS/BSD), then groff
|
|
498
|
+
renderers = [
|
|
499
|
+
["mandoc", "-a"],
|
|
500
|
+
["groff", "-man", "-Tutf8"],
|
|
501
|
+
]
|
|
502
|
+
for cmd in renderers:
|
|
503
|
+
try:
|
|
504
|
+
result = subprocess.run(
|
|
505
|
+
cmd,
|
|
506
|
+
input=roff_bytes,
|
|
507
|
+
capture_output=True,
|
|
508
|
+
)
|
|
509
|
+
except FileNotFoundError:
|
|
510
|
+
continue
|
|
511
|
+
if result.returncode == 0 and result.stdout:
|
|
512
|
+
pager = os.environ.get("PAGER", "less")
|
|
513
|
+
try:
|
|
514
|
+
subprocess.run(
|
|
515
|
+
[pager, "-R"],
|
|
516
|
+
input=result.stdout,
|
|
517
|
+
)
|
|
518
|
+
return
|
|
519
|
+
except FileNotFoundError:
|
|
520
|
+
# Pager not found — fall through to raw output
|
|
521
|
+
break
|
|
522
|
+
|
|
523
|
+
# Fallback: raw roff output
|
|
524
|
+
sys.stdout.write(roff)
|
|
525
|
+
|
|
526
|
+
|
|
483
527
|
def configure_man_help(
|
|
484
528
|
cli: click.Group,
|
|
485
529
|
prog_name: str,
|
|
@@ -520,7 +564,7 @@ def configure_man_help(
|
|
|
520
564
|
args = sys.argv[1:]
|
|
521
565
|
if "--man" in args and ("--help" in args or "-h" in args):
|
|
522
566
|
roff = build_program_man_page(cli, prog_name, version, description, docs_url)
|
|
523
|
-
|
|
567
|
+
_render_man_page(roff)
|
|
524
568
|
sys.exit(0)
|
|
525
569
|
|
|
526
570
|
|
|
@@ -140,3 +140,47 @@ class TestConfigFileLoading:
|
|
|
140
140
|
resolver = ConfigResolver(config_path="/nonexistent/apcore.yaml")
|
|
141
141
|
result = resolver._flatten_dict({"a": {"b": {"c": "deep_value"}}})
|
|
142
142
|
assert result == {"a.b.c": "deep_value"}
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
class TestNamespaceAwareConfigResolution:
|
|
146
|
+
"""Config Bus namespace ↔ legacy key fallback (apcore >= 0.15.0)."""
|
|
147
|
+
|
|
148
|
+
def test_defaults_contain_namespace_keys(self):
|
|
149
|
+
resolver = ConfigResolver()
|
|
150
|
+
for key in [
|
|
151
|
+
"apcore-cli.stdin_buffer_limit",
|
|
152
|
+
"apcore-cli.auto_approve",
|
|
153
|
+
"apcore-cli.help_text_max_length",
|
|
154
|
+
"apcore-cli.logging_level",
|
|
155
|
+
]:
|
|
156
|
+
assert key in resolver.DEFAULTS, f"Missing namespace default: {key}"
|
|
157
|
+
|
|
158
|
+
def test_resolve_namespace_key_from_legacy_config_file(self, tmp_path, clean_env):
|
|
159
|
+
"""Querying 'apcore-cli.stdin_buffer_limit' finds 'cli.stdin_buffer_limit' in file."""
|
|
160
|
+
config_file = tmp_path / "apcore.yaml"
|
|
161
|
+
config_file.write_text("cli:\n stdin_buffer_limit: 5242880\n")
|
|
162
|
+
resolver = ConfigResolver(config_path=str(config_file))
|
|
163
|
+
result = resolver.resolve("apcore-cli.stdin_buffer_limit")
|
|
164
|
+
assert result == 5242880
|
|
165
|
+
|
|
166
|
+
def test_resolve_legacy_key_from_namespace_config_file(self, tmp_path, clean_env):
|
|
167
|
+
"""Querying 'cli.auto_approve' finds 'apcore-cli.auto_approve' in file."""
|
|
168
|
+
config_file = tmp_path / "apcore.yaml"
|
|
169
|
+
config_file.write_text("apcore-cli:\n auto_approve: true\n")
|
|
170
|
+
resolver = ConfigResolver(config_path=str(config_file))
|
|
171
|
+
result = resolver.resolve("cli.auto_approve")
|
|
172
|
+
assert result is True
|
|
173
|
+
|
|
174
|
+
def test_direct_key_takes_precedence_over_alternate(self, tmp_path, clean_env):
|
|
175
|
+
"""When both keys exist in file, the directly-queried key wins."""
|
|
176
|
+
config_file = tmp_path / "apcore.yaml"
|
|
177
|
+
config_file.write_text("cli:\n help_text_max_length: 500\n" "apcore-cli:\n help_text_max_length: 2000\n")
|
|
178
|
+
resolver = ConfigResolver(config_path=str(config_file))
|
|
179
|
+
assert resolver.resolve("cli.help_text_max_length") == 500
|
|
180
|
+
assert resolver.resolve("apcore-cli.help_text_max_length") == 2000
|
|
181
|
+
|
|
182
|
+
def test_namespace_mapping_is_bidirectional(self):
|
|
183
|
+
resolver = ConfigResolver()
|
|
184
|
+
assert len(resolver._NAMESPACE_TO_LEGACY) == len(resolver._LEGACY_TO_NAMESPACE)
|
|
185
|
+
for ns_key, legacy_key in resolver._NAMESPACE_TO_LEGACY.items():
|
|
186
|
+
assert resolver._LEGACY_TO_NAMESPACE[legacy_key] == ns_key
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
"""apcore-cli: CLI adapter for the apcore module ecosystem."""
|
|
2
|
-
|
|
3
|
-
from importlib.metadata import PackageNotFoundError
|
|
4
|
-
from importlib.metadata import version as _get_version
|
|
5
|
-
|
|
6
|
-
try:
|
|
7
|
-
__version__ = _get_version("apcore-cli")
|
|
8
|
-
except PackageNotFoundError:
|
|
9
|
-
__version__ = "unknown"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|