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.
Files changed (26) hide show
  1. {chatenv-0.2.0/src/chatenv.egg-info → chatenv-0.2.1}/PKG-INFO +4 -1
  2. {chatenv-0.2.0 → chatenv-0.2.1}/README.md +3 -0
  3. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/__init__.py +1 -1
  4. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/cli.py +70 -1
  5. {chatenv-0.2.0 → chatenv-0.2.1/src/chatenv.egg-info}/PKG-INFO +4 -1
  6. {chatenv-0.2.0 → chatenv-0.2.1}/tests/test_chatenv_core.py +32 -0
  7. chatenv-0.2.1/tests/test_version.py +14 -0
  8. chatenv-0.2.0/tests/test_version.py +0 -5
  9. {chatenv-0.2.0 → chatenv-0.2.1}/LICENSE +0 -0
  10. {chatenv-0.2.0 → chatenv-0.2.1}/pyproject.toml +0 -0
  11. {chatenv-0.2.0 → chatenv-0.2.1}/setup.cfg +0 -0
  12. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/configs.py +0 -0
  13. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/discovery.py +0 -0
  14. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/fields.py +0 -0
  15. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/paste.py +0 -0
  16. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/paths.py +0 -0
  17. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/presets/__init__.py +0 -0
  18. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/registry.py +0 -0
  19. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/source_chain.py +0 -0
  20. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/store.py +0 -0
  21. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv/utils.py +0 -0
  22. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/SOURCES.txt +0 -0
  23. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/dependency_links.txt +0 -0
  24. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/entry_points.txt +0 -0
  25. {chatenv-0.2.0 → chatenv-0.2.1}/src/chatenv.egg-info/requires.txt +0 -0
  26. {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.0
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
@@ -20,4 +20,4 @@ __all__ = [
20
20
  "__version__",
21
21
  ]
22
22
 
23
- __version__ = "0.2.0"
23
+ __version__ = "0.2.1"
@@ -19,7 +19,8 @@ from chatstyle import (
19
19
  resolve_interactive_mode as _chatstyle_resolve_interactive_mode,
20
20
  )
21
21
 
22
- from .discovery import load_config_providers
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.0
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
@@ -1,5 +0,0 @@
1
- from chatenv import __version__
2
-
3
-
4
- def test_version_present():
5
- assert __version__ == "0.2.0"
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