chatenv 0.2.0__tar.gz → 0.2.1__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.
- {chatenv-0.2.0/src/chatenv.egg-info → chatenv-0.2.1}/PKG-INFO +4 -1
- {chatenv-0.2.0 → chatenv-0.2.1}/README.md +3 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/__init__.py +1 -1
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/cli.py +70 -1
- {chatenv-0.2.0 → chatenv-0.2.1/src/chatenv.egg-info}/PKG-INFO +4 -1
- {chatenv-0.2.0 → chatenv-0.2.1}/tests/test_chatenv_core.py +32 -0
- chatenv-0.2.1/tests/test_version.py +14 -0
- chatenv-0.2.0/tests/test_version.py +0 -5
- {chatenv-0.2.0 → chatenv-0.2.1}/LICENSE +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/pyproject.toml +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/setup.cfg +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/configs.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/discovery.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/fields.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/paste.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/paths.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/presets/__init__.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/registry.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/source_chain.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/store.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/utils.py +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/SOURCES.txt +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/dependency_links.txt +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/entry_points.txt +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/requires.txt +0 -0
- {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chatenv
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: ChatArch typed environment profile manager
|
|
5
5
|
Author-email: rexwzh <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -86,7 +86,10 @@ $CHATARCH_HOME/envs/
|
|
|
86
86
|
`chatenv` CLI 基于已注册 schema 工作。单独安装且没有项目注册 schema 时,它会提示需要先注册配置类型。业务项目通常会在自己的 CLI 中导入 schema 后复用这些能力。
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
+
chatenv --version
|
|
89
90
|
chatenv init -t example
|
|
91
|
+
chatenv status
|
|
92
|
+
chatenv status --detail
|
|
90
93
|
chatenv cat -t example
|
|
91
94
|
chatenv cat -t example --no-mask | chatenv paste --stdin --profile work --yes
|
|
92
95
|
chatenv set EXAMPLE_API_KEY=sk-xxx
|
|
@@ -59,7 +59,10 @@ $CHATARCH_HOME/envs/
|
|
|
59
59
|
`chatenv` CLI 基于已注册 schema 工作。单独安装且没有项目注册 schema 时,它会提示需要先注册配置类型。业务项目通常会在自己的 CLI 中导入 schema 后复用这些能力。
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
+
chatenv --version
|
|
62
63
|
chatenv init -t example
|
|
64
|
+
chatenv status
|
|
65
|
+
chatenv status --detail
|
|
63
66
|
chatenv cat -t example
|
|
64
67
|
chatenv cat -t example --no-mask | chatenv paste --stdin --profile work --yes
|
|
65
68
|
chatenv set EXAMPLE_API_KEY=sk-xxx
|
|
@@ -19,7 +19,8 @@ from chatstyle import (
|
|
|
19
19
|
resolve_interactive_mode as _chatstyle_resolve_interactive_mode,
|
|
20
20
|
)
|
|
21
21
|
|
|
22
|
-
from .
|
|
22
|
+
from . import __version__
|
|
23
|
+
from .discovery import get_provider_errors, load_config_providers
|
|
23
24
|
from .fields import BaseEnvConfig, EnvField, normalize_profile_name
|
|
24
25
|
from .paste import iter_fields_for_values, parse_pasted_env_text
|
|
25
26
|
from .paths import get_paths
|
|
@@ -104,6 +105,7 @@ COMMAND_ORDER = [
|
|
|
104
105
|
"paste",
|
|
105
106
|
"use",
|
|
106
107
|
"list",
|
|
108
|
+
"status",
|
|
107
109
|
"cat",
|
|
108
110
|
"get",
|
|
109
111
|
"set",
|
|
@@ -122,6 +124,7 @@ class OrderedGroup(click.Group):
|
|
|
122
124
|
|
|
123
125
|
|
|
124
126
|
@click.group(name="chatenv", cls=OrderedGroup)
|
|
127
|
+
@click.version_option(__version__, prog_name="chatenv")
|
|
125
128
|
@click.option("--home", type=click.Path(file_okay=False, path_type=Path), help="Override CHATARCH_HOME for this command.")
|
|
126
129
|
@click.pass_context
|
|
127
130
|
def cli(ctx: click.Context, home: Path | None):
|
|
@@ -187,6 +190,43 @@ def _available_config_types_message() -> str:
|
|
|
187
190
|
return "\n".join(lines)
|
|
188
191
|
|
|
189
192
|
|
|
193
|
+
def _provider_name(config_cls: type[BaseEnvConfig]) -> str:
|
|
194
|
+
return str(getattr(config_cls, "_provider", config_cls.__module__.split(".", 1)[0]))
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def _status_config_line(config_cls: type[BaseEnvConfig], store: EnvStore) -> str:
|
|
198
|
+
aliases = ",".join(getattr(config_cls, "_aliases", [])) or "-"
|
|
199
|
+
profiles = store.list_profiles(config_cls)
|
|
200
|
+
active_marker = "yes" if store.active_path(config_cls).exists() else "no"
|
|
201
|
+
return (
|
|
202
|
+
f"- {config_cls.get_storage_name()} | title={config_cls._title} | "
|
|
203
|
+
f"provider={_provider_name(config_cls)} | aliases={aliases} | "
|
|
204
|
+
f"fields={len(config_cls.get_fields())} | active={active_marker} | profiles={len(profiles)}"
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _status_field_line(config_cls: type[BaseEnvConfig], field_name: str, field: EnvField) -> str:
|
|
209
|
+
value_set = field.value not in (None, "")
|
|
210
|
+
default = field.default
|
|
211
|
+
if field.is_sensitive and default not in (None, ""):
|
|
212
|
+
default_text = mask_secret(str(default))
|
|
213
|
+
else:
|
|
214
|
+
default_text = "" if default is None else str(default)
|
|
215
|
+
parts = [
|
|
216
|
+
f" - {field.env_key}",
|
|
217
|
+
f"name={field_name}",
|
|
218
|
+
f"provider={_provider_name(config_cls)}",
|
|
219
|
+
]
|
|
220
|
+
if field.desc:
|
|
221
|
+
parts.append(f"desc={field.desc}")
|
|
222
|
+
if default_text:
|
|
223
|
+
parts.append(f"default={default_text}")
|
|
224
|
+
if field.is_sensitive:
|
|
225
|
+
parts.append("sensitive=yes")
|
|
226
|
+
parts.append(f"configured={'yes' if value_set else 'no'}")
|
|
227
|
+
return " | ".join(parts)
|
|
228
|
+
|
|
229
|
+
|
|
190
230
|
def _select_config_interactive(
|
|
191
231
|
*,
|
|
192
232
|
action: str,
|
|
@@ -360,6 +400,35 @@ def list_env(ctx: click.Context, config_types: tuple[str, ...]):
|
|
|
360
400
|
click.echo(f"No profiles found under {_envs_dir(ctx)}")
|
|
361
401
|
|
|
362
402
|
|
|
403
|
+
@cli.command(name="status")
|
|
404
|
+
@click.option("--type", "config_types", "-t", multiple=True, help="Filter config types.")
|
|
405
|
+
@click.option("--detail", is_flag=True, help="Show each registered variable and its provider package.")
|
|
406
|
+
@click.pass_context
|
|
407
|
+
def status_env(ctx: click.Context, config_types: tuple[str, ...], detail: bool):
|
|
408
|
+
"""Show registered config platforms and provider ownership."""
|
|
409
|
+
store = _store(ctx)
|
|
410
|
+
configs = _matched_or_all(config_types)
|
|
411
|
+
_ensure_registered()
|
|
412
|
+
if config_types and not configs:
|
|
413
|
+
raise click.ClickException(f"No configuration types matched: {', '.join(config_types)}")
|
|
414
|
+
_load_all(ctx)
|
|
415
|
+
click.echo(f"Registered config platforms: {len(configs)}")
|
|
416
|
+
for index, config_cls in enumerate(configs):
|
|
417
|
+
if index:
|
|
418
|
+
click.echo("")
|
|
419
|
+
click.echo(_status_config_line(config_cls, store))
|
|
420
|
+
if not detail:
|
|
421
|
+
continue
|
|
422
|
+
for field_name, field in config_cls.get_fields().items():
|
|
423
|
+
click.echo(_status_field_line(config_cls, field_name, field))
|
|
424
|
+
errors = get_provider_errors()
|
|
425
|
+
if errors:
|
|
426
|
+
click.echo("")
|
|
427
|
+
click.echo(f"Provider load errors: {len(errors)}")
|
|
428
|
+
for provider, exc in errors.items():
|
|
429
|
+
click.echo(f"- {provider}: {exc}")
|
|
430
|
+
|
|
431
|
+
|
|
363
432
|
@cli.command(name="cat")
|
|
364
433
|
@click.argument("name", required=False)
|
|
365
434
|
@click.option("--no-mask", is_flag=True, help="Show sensitive values in plain text.")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: chatenv
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: ChatArch typed environment profile manager
|
|
5
5
|
Author-email: rexwzh <1073853456@qq.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -86,7 +86,10 @@ $CHATARCH_HOME/envs/
|
|
|
86
86
|
`chatenv` CLI 基于已注册 schema 工作。单独安装且没有项目注册 schema 时,它会提示需要先注册配置类型。业务项目通常会在自己的 CLI 中导入 schema 后复用这些能力。
|
|
87
87
|
|
|
88
88
|
```bash
|
|
89
|
+
chatenv --version
|
|
89
90
|
chatenv init -t example
|
|
91
|
+
chatenv status
|
|
92
|
+
chatenv status --detail
|
|
90
93
|
chatenv cat -t example
|
|
91
94
|
chatenv cat -t example --no-mask | chatenv paste --stdin --profile work --yes
|
|
92
95
|
chatenv set EXAMPLE_API_KEY=sk-xxx
|
|
@@ -101,6 +101,37 @@ def test_chatarch_internal_dependencies_have_upper_bounds():
|
|
|
101
101
|
assert '"chatstyle>=0.1.0"' not in pyproject_text
|
|
102
102
|
|
|
103
103
|
|
|
104
|
+
def test_status_lists_registered_platforms_and_provider_detail(tmp_path):
|
|
105
|
+
runner = CliRunner()
|
|
106
|
+
home = tmp_path / "arch"
|
|
107
|
+
result = runner.invoke(cli, ["--home", str(home), "status", "--type", "unit", "--detail"])
|
|
108
|
+
|
|
109
|
+
assert result.exit_code == 0, result.output
|
|
110
|
+
assert "Registered config platforms: 1" in result.output
|
|
111
|
+
assert "Unit | title=Unit Configuration" in result.output
|
|
112
|
+
assert "provider=" in result.output
|
|
113
|
+
assert "UNIT_KEY" in result.output
|
|
114
|
+
assert "sensitive=yes" in result.output
|
|
115
|
+
assert "UNIT_VALUE" in result.output
|
|
116
|
+
assert "default=default" in result.output
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_status_reports_provider_name_from_loaded_package(tmp_path):
|
|
120
|
+
previous = getattr(UnitConfig, "_provider", None)
|
|
121
|
+
setattr(UnitConfig, "_provider", "chatunit")
|
|
122
|
+
try:
|
|
123
|
+
result = CliRunner().invoke(cli, ["--home", str(tmp_path / "arch"), "status", "--type", "unit", "--detail"])
|
|
124
|
+
finally:
|
|
125
|
+
if previous is None:
|
|
126
|
+
delattr(UnitConfig, "_provider")
|
|
127
|
+
else:
|
|
128
|
+
setattr(UnitConfig, "_provider", previous)
|
|
129
|
+
|
|
130
|
+
assert result.exit_code == 0, result.output
|
|
131
|
+
assert "provider=chatunit" in result.output
|
|
132
|
+
assert "UNIT_KEY | name=UNIT_KEY | provider=chatunit" in result.output
|
|
133
|
+
|
|
134
|
+
|
|
104
135
|
def test_cli_set_only_writes_the_requested_key(monkeypatch, tmp_path):
|
|
105
136
|
monkeypatch.setenv("OPENAI_API_KEY", "system-secret")
|
|
106
137
|
runner = CliRunner()
|
|
@@ -548,6 +579,7 @@ def test_cli_help_uses_stable_command_order():
|
|
|
548
579
|
"paste",
|
|
549
580
|
"use",
|
|
550
581
|
"list",
|
|
582
|
+
"status",
|
|
551
583
|
"cat",
|
|
552
584
|
"get",
|
|
553
585
|
"set",
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from chatenv import __version__
|
|
2
|
+
from chatenv.cli import cli
|
|
3
|
+
from click.testing import CliRunner
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def test_version_present():
|
|
7
|
+
assert __version__ == "0.2.1"
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def test_cli_version_option():
|
|
11
|
+
result = CliRunner().invoke(cli, ["--version"])
|
|
12
|
+
|
|
13
|
+
assert result.exit_code == 0
|
|
14
|
+
assert __version__ in result.output
|
|
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
|