parseforge 0.2.3__tar.gz → 0.2.4__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 (44) hide show
  1. {parseforge-0.2.3/parseforge.egg-info → parseforge-0.2.4}/PKG-INFO +36 -4
  2. {parseforge-0.2.3 → parseforge-0.2.4}/README.md +23 -0
  3. parseforge-0.2.4/parseforge/__init__.py +1 -0
  4. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/generation.py +6 -1
  5. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/anthropic.py +27 -7
  6. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/deepseek.py +25 -7
  7. {parseforge-0.2.3 → parseforge-0.2.4/parseforge.egg-info}/PKG-INFO +36 -4
  8. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge.egg-info/requires.txt +13 -1
  9. {parseforge-0.2.3 → parseforge-0.2.4}/pyproject.toml +22 -4
  10. parseforge-0.2.3/parseforge/__init__.py +0 -1
  11. {parseforge-0.2.3 → parseforge-0.2.4}/LICENSE +0 -0
  12. {parseforge-0.2.3 → parseforge-0.2.4}/MANIFEST.in +0 -0
  13. {parseforge-0.2.3 → parseforge-0.2.4}/SPEC.md +0 -0
  14. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/cli/__init__.py +0 -0
  15. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/cli/config.py +0 -0
  16. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/cli/main.py +0 -0
  17. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/drift.py +0 -0
  18. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/integration.py +0 -0
  19. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/__init__.py +0 -0
  20. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/assemble.py +0 -0
  21. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/cache.py +0 -0
  22. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/llm.py +0 -0
  23. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/prompts.py +0 -0
  24. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/prompts.yaml +0 -0
  25. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/__init__.py +0 -0
  26. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/cost.py +0 -0
  27. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/errors.py +0 -0
  28. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/models.py +0 -0
  29. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/models.yaml +0 -0
  30. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/providers/text.py +0 -0
  31. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/naming/resolver.py +0 -0
  32. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/paths.py +0 -0
  33. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/pipeline.py +0 -0
  34. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/promotion.py +0 -0
  35. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/sampling/__init__.py +0 -0
  36. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/sampling/backends/__init__.py +0 -0
  37. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/sampling/backends/netmiko.py +0 -0
  38. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/sampling/core.py +0 -0
  39. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge/validation.py +0 -0
  40. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge.egg-info/SOURCES.txt +0 -0
  41. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge.egg-info/dependency_links.txt +0 -0
  42. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge.egg-info/entry_points.txt +0 -0
  43. {parseforge-0.2.3 → parseforge-0.2.4}/parseforge.egg-info/top_level.txt +0 -0
  44. {parseforge-0.2.3 → parseforge-0.2.4}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: parseforge
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: LLM-driven pipeline that forges, validates, and promotes TextFSM templates from network CLI output
5
5
  Author-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
6
6
  Maintainer-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
@@ -26,9 +26,13 @@ License-File: LICENSE
26
26
  Requires-Dist: click>=8.1
27
27
  Requires-Dist: PyYAML>=6.0
28
28
  Requires-Dist: textfsm>=1.1.0
29
- Requires-Dist: anthropic>=0.40.0
30
- Requires-Dist: openai>=1.0.0
31
- Requires-Dist: textfsm-ai>=0.5.1
29
+ Requires-Dist: textfsm-ai>=0.6.1
30
+ Provides-Extra: anthropic
31
+ Requires-Dist: anthropic>=0.40.0; extra == "anthropic"
32
+ Requires-Dist: textfsm-ai[anthropic]>=0.6.1; extra == "anthropic"
33
+ Provides-Extra: deepseek
34
+ Requires-Dist: openai>=1.0.0; extra == "deepseek"
35
+ Requires-Dist: textfsm-ai[deepseek]>=0.6.1; extra == "deepseek"
32
36
  Provides-Extra: sampling
33
37
  Requires-Dist: netmiko>=4.0; extra == "sampling"
34
38
  Provides-Extra: dev
@@ -37,6 +41,11 @@ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
37
41
  Requires-Dist: ruff>=0.4.0; extra == "dev"
38
42
  Requires-Dist: black>=24.0.0; extra == "dev"
39
43
  Requires-Dist: mypy>=1.10.0; extra == "dev"
44
+ Requires-Dist: anthropic>=0.40.0; extra == "dev"
45
+ Requires-Dist: openai>=1.0.0; extra == "dev"
46
+ Provides-Extra: release
47
+ Requires-Dist: bump2version; extra == "release"
48
+ Requires-Dist: build; extra == "release"
40
49
  Dynamic: license-file
41
50
 
42
51
  # ParseForge
@@ -65,12 +74,35 @@ wired into the CLI below. A few things are intentionally not there yet:
65
74
  - **One sampling connector** (Netmiko/SSH). The CLI's `--connector` registry
66
75
  is built to hold more without a redesign, but nothing else is wired in yet.
67
76
 
77
+ ## Installation
78
+
79
+ ```
80
+ pip install parseforge[anthropic]
81
+ ```
82
+ `pip install parseforge` alone installs no AI-provider SDK at all — every
83
+ command that's pure local processing (`canonical`/`readable`/`recognizers`,
84
+ `integration`, `promotion`) works with nothing further. Anything that calls an
85
+ LLM (`name`, `check --provider`, `run`, `generate-template`, `trial`) needs the
86
+ extra for whichever provider it uses: `anthropic` or `deepseek`. `--provider`
87
+ defaults to `anthropic` wherever it isn't required, so that's the one most
88
+ setups need. `pip install parseforge[sampling]` adds Netmiko for live device
89
+ sampling; combine extras as needed, e.g.
90
+ `pip install parseforge[anthropic,deepseek,sampling]`.
91
+
68
92
  ## Development
69
93
 
70
94
  ```
71
95
  pip install -e ".[dev,sampling]"
72
96
  pytest
73
97
  ```
98
+ `dev` already includes both `anthropic` and `openai` (tests exercise both
99
+ providers, never silently skip) — add `,anthropic`/`,deepseek` explicitly only
100
+ if installing outside of `dev`.
101
+
102
+ Linting/formatting/type-checking/docs run through tox instead of extras — see
103
+ `tox.ini` (`tox -e lint`/`format`/`typecheck`/`docs`), each installing its own
104
+ tools in an isolated env. Cutting a release needs `pip install -e ".[release]"`
105
+ (`bump2version`, `build`) — see `scripts/release.ps1`.
74
106
 
75
107
  ## CLI
76
108
 
@@ -24,12 +24,35 @@ wired into the CLI below. A few things are intentionally not there yet:
24
24
  - **One sampling connector** (Netmiko/SSH). The CLI's `--connector` registry
25
25
  is built to hold more without a redesign, but nothing else is wired in yet.
26
26
 
27
+ ## Installation
28
+
29
+ ```
30
+ pip install parseforge[anthropic]
31
+ ```
32
+ `pip install parseforge` alone installs no AI-provider SDK at all — every
33
+ command that's pure local processing (`canonical`/`readable`/`recognizers`,
34
+ `integration`, `promotion`) works with nothing further. Anything that calls an
35
+ LLM (`name`, `check --provider`, `run`, `generate-template`, `trial`) needs the
36
+ extra for whichever provider it uses: `anthropic` or `deepseek`. `--provider`
37
+ defaults to `anthropic` wherever it isn't required, so that's the one most
38
+ setups need. `pip install parseforge[sampling]` adds Netmiko for live device
39
+ sampling; combine extras as needed, e.g.
40
+ `pip install parseforge[anthropic,deepseek,sampling]`.
41
+
27
42
  ## Development
28
43
 
29
44
  ```
30
45
  pip install -e ".[dev,sampling]"
31
46
  pytest
32
47
  ```
48
+ `dev` already includes both `anthropic` and `openai` (tests exercise both
49
+ providers, never silently skip) — add `,anthropic`/`,deepseek` explicitly only
50
+ if installing outside of `dev`.
51
+
52
+ Linting/formatting/type-checking/docs run through tox instead of extras — see
53
+ `tox.ini` (`tox -e lint`/`format`/`typecheck`/`docs`), each installing its own
54
+ tools in an isolated env. Cutting a release needs `pip install -e ".[release]"`
55
+ (`bump2version`, `build`) — see `scripts/release.ps1`.
33
56
 
34
57
  ## CLI
35
58
 
@@ -0,0 +1 @@
1
+ __version__ = "0.2.4"
@@ -78,7 +78,12 @@ def generate(
78
78
  forwards to ``run_pipeline()`` for everything else (``endpoint``,
79
79
  ``region``, ``max_tries``, ...).
80
80
 
81
- Never raises for a failed generation check ``.ready``.
81
+ Never raises for a failed *generation* (a bad/truncated LLM response) —
82
+ check ``.ready`` for that. Does raise ``ImportError`` if ``provider``'s
83
+ SDK isn't installed (textfsm-ai's own lazy provider registry, pointing
84
+ at the right ``pip install textfsm-ai[<provider>]`` extra) — a missing
85
+ package is an environment problem, not a generation outcome, and is
86
+ treated the same way here as in :mod:`parseforge.naming.providers`.
82
87
  """
83
88
  result = run_pipeline(
84
89
  sample, provider, api_key, model, mode="debug", as_json=True, **kwargs
@@ -3,9 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import time
6
- from typing import Any
7
-
8
- from anthropic import Anthropic, AnthropicError
6
+ from typing import TYPE_CHECKING, Any
9
7
 
10
8
  from ..llm import CliContext, LLMCLIResponse, TokenUsage, build_prompt
11
9
  from .cost import estimate_cost
@@ -13,6 +11,9 @@ from .errors import format_llm_error_reason, is_retryable
13
11
  from .models import default_model
14
12
  from .text import extract_pattern
15
13
 
14
+ if TYPE_CHECKING:
15
+ import anthropic as anthropic_sdk
16
+
16
17
  DEFAULT_MODEL = default_model("anthropic")
17
18
 
18
19
  # Headroom in case a future/opt-in extended-thinking model burns part of
@@ -21,6 +22,21 @@ DEFAULT_MODEL = default_model("anthropic")
21
22
  _DEFAULT_MAX_TOKENS = 1024
22
23
 
23
24
 
25
+ def _import_anthropic() -> Any:
26
+ """Deferred import — anthropic is an optional extra (parseforge[anthropic]);
27
+ nothing else in this module (or a cache-hit lookup, which never reaches
28
+ build_pattern at all — see resolver.cli_name) should require it to be
29
+ installed."""
30
+ try:
31
+ import anthropic
32
+ except ImportError as exc:
33
+ raise ImportError(
34
+ "the anthropic package is required to use AnthropicRegexBuilder — "
35
+ "install it via `pip install parseforge[anthropic]`"
36
+ ) from exc
37
+ return anthropic
38
+
39
+
24
40
  class AnthropicRegexBuilder:
25
41
  """Builds a cli-name regex pattern by prompting a Claude model.
26
42
 
@@ -38,18 +54,22 @@ class AnthropicRegexBuilder:
38
54
  def __init__(self, model: str = DEFAULT_MODEL, api_key: str | None = None) -> None:
39
55
  self.model = model
40
56
  self._api_key = api_key
41
- self._client: Anthropic | None = None
57
+ self._client: anthropic_sdk.Anthropic | None = None
42
58
 
43
- def _get_client(self) -> Anthropic:
59
+ def _get_client(self) -> anthropic_sdk.Anthropic:
44
60
  if self._client is None:
61
+ anthropic = _import_anthropic()
45
62
  self._client = (
46
- Anthropic(api_key=self._api_key) if self._api_key else Anthropic()
63
+ anthropic.Anthropic(api_key=self._api_key)
64
+ if self._api_key
65
+ else anthropic.Anthropic()
47
66
  )
48
67
  return self._client
49
68
 
50
69
  def build_pattern(
51
70
  self, command: str, context: CliContext, **kwargs: Any
52
71
  ) -> LLMCLIResponse:
72
+ anthropic = _import_anthropic()
53
73
  prompt = build_prompt(command, context)
54
74
  max_tokens = kwargs.pop("max_tokens", None) or _DEFAULT_MAX_TOKENS
55
75
 
@@ -61,7 +81,7 @@ class AnthropicRegexBuilder:
61
81
  messages=[{"role": "user", "content": prompt}],
62
82
  **kwargs,
63
83
  )
64
- except AnthropicError as exc:
84
+ except anthropic.AnthropicError as exc:
65
85
  if not is_retryable(exc):
66
86
  # Same request would fail the same way again — stop rather
67
87
  # than let a caller burn another attempt on it.
@@ -9,9 +9,7 @@ from __future__ import annotations
9
9
 
10
10
  import os
11
11
  import time
12
- from typing import Any
13
-
14
- from openai import OpenAI, OpenAIError
12
+ from typing import TYPE_CHECKING, Any
15
13
 
16
14
  from ..llm import CliContext, LLMCLIResponse, TokenUsage, build_prompt
17
15
  from .cost import estimate_cost
@@ -19,6 +17,9 @@ from .errors import format_llm_error_reason, is_retryable
19
17
  from .models import default_model
20
18
  from .text import extract_pattern
21
19
 
20
+ if TYPE_CHECKING:
21
+ import openai as openai_sdk
22
+
22
23
  DEFAULT_MODEL = default_model("deepseek")
23
24
 
24
25
  _BASE_URL = "https://api.deepseek.com"
@@ -34,6 +35,21 @@ _DEFAULT_MAX_TOKENS = 1024
34
35
  _THINKING_DISABLED = {"thinking": {"type": "disabled"}}
35
36
 
36
37
 
38
+ def _import_openai() -> Any:
39
+ """Deferred import — openai is an optional extra (parseforge[deepseek]);
40
+ nothing else in this module (or a cache-hit lookup, which never reaches
41
+ build_pattern at all — see resolver.cli_name) should require it to be
42
+ installed."""
43
+ try:
44
+ import openai
45
+ except ImportError as exc:
46
+ raise ImportError(
47
+ "the openai package is required to use DeepSeekRegexBuilder — "
48
+ "install it via `pip install parseforge[deepseek]`"
49
+ ) from exc
50
+ return openai
51
+
52
+
37
53
  class DeepSeekRegexBuilder:
38
54
  """Builds a cli-name regex pattern by prompting a DeepSeek model.
39
55
 
@@ -53,21 +69,23 @@ class DeepSeekRegexBuilder:
53
69
  def __init__(self, model: str = DEFAULT_MODEL, api_key: str | None = None) -> None:
54
70
  self.model = model
55
71
  self._api_key = api_key
56
- self._client: OpenAI | None = None
72
+ self._client: openai_sdk.OpenAI | None = None
57
73
 
58
- def _get_client(self) -> OpenAI:
74
+ def _get_client(self) -> openai_sdk.OpenAI:
59
75
  if self._client is None:
76
+ openai = _import_openai()
60
77
  api_key = self._api_key or os.environ.get("DEEPSEEK_API_KEY")
61
78
  if not api_key:
62
79
  raise RuntimeError(
63
80
  "no DeepSeek API key — pass api_key or set DEEPSEEK_API_KEY"
64
81
  )
65
- self._client = OpenAI(api_key=api_key, base_url=_BASE_URL)
82
+ self._client = openai.OpenAI(api_key=api_key, base_url=_BASE_URL)
66
83
  return self._client
67
84
 
68
85
  def build_pattern(
69
86
  self, command: str, context: CliContext, **kwargs: Any
70
87
  ) -> LLMCLIResponse:
88
+ openai = _import_openai()
71
89
  prompt = build_prompt(command, context)
72
90
  # Callers can override either of these per-call (e.g. re-enable
73
91
  # thinking mode, raise max_tokens further); anything else in
@@ -84,7 +102,7 @@ class DeepSeekRegexBuilder:
84
102
  extra_body=extra_body,
85
103
  **kwargs,
86
104
  )
87
- except OpenAIError as exc:
105
+ except openai.OpenAIError as exc:
88
106
  if not is_retryable(exc):
89
107
  # Same request would fail the same way again — stop rather
90
108
  # than let a caller burn another attempt on it.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: parseforge
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: LLM-driven pipeline that forges, validates, and promotes TextFSM templates from network CLI output
5
5
  Author-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
6
6
  Maintainer-email: Tuyen Mathew Duong <tuyen@geekstrident.com>
@@ -26,9 +26,13 @@ License-File: LICENSE
26
26
  Requires-Dist: click>=8.1
27
27
  Requires-Dist: PyYAML>=6.0
28
28
  Requires-Dist: textfsm>=1.1.0
29
- Requires-Dist: anthropic>=0.40.0
30
- Requires-Dist: openai>=1.0.0
31
- Requires-Dist: textfsm-ai>=0.5.1
29
+ Requires-Dist: textfsm-ai>=0.6.1
30
+ Provides-Extra: anthropic
31
+ Requires-Dist: anthropic>=0.40.0; extra == "anthropic"
32
+ Requires-Dist: textfsm-ai[anthropic]>=0.6.1; extra == "anthropic"
33
+ Provides-Extra: deepseek
34
+ Requires-Dist: openai>=1.0.0; extra == "deepseek"
35
+ Requires-Dist: textfsm-ai[deepseek]>=0.6.1; extra == "deepseek"
32
36
  Provides-Extra: sampling
33
37
  Requires-Dist: netmiko>=4.0; extra == "sampling"
34
38
  Provides-Extra: dev
@@ -37,6 +41,11 @@ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
37
41
  Requires-Dist: ruff>=0.4.0; extra == "dev"
38
42
  Requires-Dist: black>=24.0.0; extra == "dev"
39
43
  Requires-Dist: mypy>=1.10.0; extra == "dev"
44
+ Requires-Dist: anthropic>=0.40.0; extra == "dev"
45
+ Requires-Dist: openai>=1.0.0; extra == "dev"
46
+ Provides-Extra: release
47
+ Requires-Dist: bump2version; extra == "release"
48
+ Requires-Dist: build; extra == "release"
40
49
  Dynamic: license-file
41
50
 
42
51
  # ParseForge
@@ -65,12 +74,35 @@ wired into the CLI below. A few things are intentionally not there yet:
65
74
  - **One sampling connector** (Netmiko/SSH). The CLI's `--connector` registry
66
75
  is built to hold more without a redesign, but nothing else is wired in yet.
67
76
 
77
+ ## Installation
78
+
79
+ ```
80
+ pip install parseforge[anthropic]
81
+ ```
82
+ `pip install parseforge` alone installs no AI-provider SDK at all — every
83
+ command that's pure local processing (`canonical`/`readable`/`recognizers`,
84
+ `integration`, `promotion`) works with nothing further. Anything that calls an
85
+ LLM (`name`, `check --provider`, `run`, `generate-template`, `trial`) needs the
86
+ extra for whichever provider it uses: `anthropic` or `deepseek`. `--provider`
87
+ defaults to `anthropic` wherever it isn't required, so that's the one most
88
+ setups need. `pip install parseforge[sampling]` adds Netmiko for live device
89
+ sampling; combine extras as needed, e.g.
90
+ `pip install parseforge[anthropic,deepseek,sampling]`.
91
+
68
92
  ## Development
69
93
 
70
94
  ```
71
95
  pip install -e ".[dev,sampling]"
72
96
  pytest
73
97
  ```
98
+ `dev` already includes both `anthropic` and `openai` (tests exercise both
99
+ providers, never silently skip) — add `,anthropic`/`,deepseek` explicitly only
100
+ if installing outside of `dev`.
101
+
102
+ Linting/formatting/type-checking/docs run through tox instead of extras — see
103
+ `tox.ini` (`tox -e lint`/`format`/`typecheck`/`docs`), each installing its own
104
+ tools in an isolated env. Cutting a release needs `pip install -e ".[release]"`
105
+ (`bump2version`, `build`) — see `scripts/release.ps1`.
74
106
 
75
107
  ## CLI
76
108
 
@@ -1,9 +1,15 @@
1
1
  click>=8.1
2
2
  PyYAML>=6.0
3
3
  textfsm>=1.1.0
4
+ textfsm-ai>=0.6.1
5
+
6
+ [anthropic]
4
7
  anthropic>=0.40.0
8
+ textfsm-ai[anthropic]>=0.6.1
9
+
10
+ [deepseek]
5
11
  openai>=1.0.0
6
- textfsm-ai>=0.5.1
12
+ textfsm-ai[deepseek]>=0.6.1
7
13
 
8
14
  [dev]
9
15
  pytest>=8.0.0
@@ -11,6 +17,12 @@ pytest-cov>=5.0.0
11
17
  ruff>=0.4.0
12
18
  black>=24.0.0
13
19
  mypy>=1.10.0
20
+ anthropic>=0.40.0
21
+ openai>=1.0.0
22
+
23
+ [release]
24
+ bump2version
25
+ build
14
26
 
15
27
  [sampling]
16
28
  netmiko>=4.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "parseforge"
7
- version = "0.2.3"
7
+ version = "0.2.4"
8
8
  description = "LLM-driven pipeline that forges, validates, and promotes TextFSM templates from network CLI output"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -22,9 +22,7 @@ dependencies = [
22
22
  "click>=8.1",
23
23
  "PyYAML>=6.0",
24
24
  "textfsm>=1.1.0",
25
- "anthropic>=0.40.0",
26
- "openai>=1.0.0",
27
- "textfsm-ai>=0.5.1",
25
+ "textfsm-ai>=0.6.1",
28
26
  ]
29
27
 
30
28
  classifiers = [
@@ -59,6 +57,13 @@ keywords = [
59
57
  ]
60
58
 
61
59
  [project.optional-dependencies]
60
+ # textfsm-ai v0.6.0+ made every provider SDK an optional extra (lazy
61
+ # import; a clear ImportError only when that provider is actually used).
62
+ # parseforge mirrors that per-provider: `pip install parseforge` alone
63
+ # now installs no AI-provider SDK at all -- add the extra(s) for the
64
+ # provider(s) you actually use.
65
+ anthropic = ["anthropic>=0.40.0", "textfsm-ai[anthropic]>=0.6.1"]
66
+ deepseek = ["openai>=1.0.0", "textfsm-ai[deepseek]>=0.6.1"]
62
67
  sampling = ["netmiko>=4.0"]
63
68
  dev = [
64
69
  "pytest>=8.0.0",
@@ -66,6 +71,19 @@ dev = [
66
71
  "ruff>=0.4.0",
67
72
  "black>=24.0.0",
68
73
  "mypy>=1.10.0",
74
+ # anthropic/openai are optional at runtime (see the extras above), but
75
+ # both providers are exercised by the CLI/tests, which should never
76
+ # silently skip -- so dev always pulls both in.
77
+ "anthropic>=0.40.0",
78
+ "openai>=1.0.0",
79
+ ]
80
+ # Tooling for scripts/release.ps1 and CI's own package-build step.
81
+ # bump2version isn't otherwise installed anywhere -- release.ps1 assumes
82
+ # it's already on PATH. twine is deliberately not here: the actual PyPI
83
+ # publish goes through pypa/gh-action-pypi-publish, not `twine upload`.
84
+ release = [
85
+ "bump2version",
86
+ "build",
69
87
  ]
70
88
 
71
89
  [project.scripts]
@@ -1 +0,0 @@
1
- __version__ = "0.2.3"
File without changes
File without changes
File without changes
File without changes