astoncli 0.1.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.
- {astoncli-0.1.0 → astoncli-0.2.1}/PKG-INFO +16 -2
- {astoncli-0.1.0 → astoncli-0.2.1}/README.md +16 -2
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/axios.py +1 -1
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/config.py +25 -3
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/ingestion.py +29 -13
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/llm.py +7 -2
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/pipeline.py +3 -3
- {astoncli-0.1.0 → astoncli-0.2.1}/astoncli.egg-info/PKG-INFO +16 -2
- {astoncli-0.1.0 → astoncli-0.2.1}/pyproject.toml +1 -1
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/__init__.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/docker.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/exceptions.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/poller.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/relevance.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/repo_verification.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/rule_validation.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/scanner.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/aston/watcher.py +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/astoncli.egg-info/SOURCES.txt +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/astoncli.egg-info/dependency_links.txt +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/astoncli.egg-info/entry_points.txt +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/astoncli.egg-info/requires.txt +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/astoncli.egg-info/top_level.txt +0 -0
- {astoncli-0.1.0 → astoncli-0.2.1}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: astoncli
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Automated Python repository migration CLI tool
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -38,6 +38,7 @@ https://github.com/user-attachments/assets/812a1990-13c3-4c45-8a8e-080f602c7a3f
|
|
|
38
38
|
|
|
39
39
|
### Automated dependency migration, from breaking-change detection to a verified pull request.
|
|
40
40
|
|
|
41
|
+

|
|
41
42
|

|
|
42
43
|

|
|
43
44
|

|
|
@@ -735,6 +736,17 @@ Instead of manually hunting down every affected API, you receive a **pull reques
|
|
|
735
736
|
|
|
736
737
|
## Installation
|
|
737
738
|
|
|
739
|
+
### From PyPI (recommended)
|
|
740
|
+
|
|
741
|
+
```bash
|
|
742
|
+
pip install astoncli
|
|
743
|
+
aston --help
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
The package is named `astoncli` on PyPI, and the command it installs is `aston`.
|
|
747
|
+
|
|
748
|
+
### From source
|
|
749
|
+
|
|
738
750
|
```bash
|
|
739
751
|
# 1. Clone
|
|
740
752
|
git clone https://github.com/2022n02511-stack/ASTon.git
|
|
@@ -752,6 +764,8 @@ aston --help
|
|
|
752
764
|
|
|
753
765
|
Then configure the environment variables required by your selected **LLM provider** and **GitHub integration**. A template is provided in `.env.example`.
|
|
754
766
|
|
|
767
|
+
> **External requirements:** Docker must be installed and running, and you need an API key for your LLM provider and a GitHub token for pull requests. Installing the package does not provide these.
|
|
768
|
+
|
|
755
769
|
---
|
|
756
770
|
|
|
757
771
|
## Design principles
|
|
@@ -782,7 +796,7 @@ The architecture separates ingestion, rule extraction, repository analysis, code
|
|
|
782
796
|
- [ ] Version-aware rule validation across more version chains (in progress)
|
|
783
797
|
- [ ] Reliability across more real-world repositories
|
|
784
798
|
- [ ] Support for additional Python packages
|
|
785
|
-
- [
|
|
799
|
+
- [x] `pip install astoncli` distribution
|
|
786
800
|
- [ ] Broader language ecosystem support
|
|
787
801
|
|
|
788
802
|
---
|
|
@@ -18,6 +18,7 @@ https://github.com/user-attachments/assets/812a1990-13c3-4c45-8a8e-080f602c7a3f
|
|
|
18
18
|
|
|
19
19
|
### Automated dependency migration, from breaking-change detection to a verified pull request.
|
|
20
20
|
|
|
21
|
+

|
|
21
22
|

|
|
22
23
|

|
|
23
24
|

|
|
@@ -715,6 +716,17 @@ Instead of manually hunting down every affected API, you receive a **pull reques
|
|
|
715
716
|
|
|
716
717
|
## Installation
|
|
717
718
|
|
|
719
|
+
### From PyPI (recommended)
|
|
720
|
+
|
|
721
|
+
```bash
|
|
722
|
+
pip install astoncli
|
|
723
|
+
aston --help
|
|
724
|
+
```
|
|
725
|
+
|
|
726
|
+
The package is named `astoncli` on PyPI, and the command it installs is `aston`.
|
|
727
|
+
|
|
728
|
+
### From source
|
|
729
|
+
|
|
718
730
|
```bash
|
|
719
731
|
# 1. Clone
|
|
720
732
|
git clone https://github.com/2022n02511-stack/ASTon.git
|
|
@@ -732,6 +744,8 @@ aston --help
|
|
|
732
744
|
|
|
733
745
|
Then configure the environment variables required by your selected **LLM provider** and **GitHub integration**. A template is provided in `.env.example`.
|
|
734
746
|
|
|
747
|
+
> **External requirements:** Docker must be installed and running, and you need an API key for your LLM provider and a GitHub token for pull requests. Installing the package does not provide these.
|
|
748
|
+
|
|
735
749
|
---
|
|
736
750
|
|
|
737
751
|
## Design principles
|
|
@@ -762,7 +776,7 @@ The architecture separates ingestion, rule extraction, repository analysis, code
|
|
|
762
776
|
- [ ] Version-aware rule validation across more version chains (in progress)
|
|
763
777
|
- [ ] Reliability across more real-world repositories
|
|
764
778
|
- [ ] Support for additional Python packages
|
|
765
|
-
- [
|
|
779
|
+
- [x] `pip install astoncli` distribution
|
|
766
780
|
- [ ] Broader language ecosystem support
|
|
767
781
|
|
|
768
782
|
---
|
|
@@ -860,4 +874,4 @@ These details make problems far easier to reproduce and investigate.
|
|
|
860
874
|
|
|
861
875
|
If ASTon saves you time, consider starring the repo.
|
|
862
876
|
|
|
863
|
-
</div>
|
|
877
|
+
</div>
|
|
@@ -27,6 +27,15 @@ DEFAULT_CONFIG = {
|
|
|
27
27
|
},
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
# Runtime overrides storage (populated by CLI flags before execution)
|
|
31
|
+
_RUNTIME_OVERRIDES = {}
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def set_runtime_config(overrides: dict):
|
|
35
|
+
"""Set temporary runtime configuration overrides from CLI flags."""
|
|
36
|
+
global _RUNTIME_OVERRIDES
|
|
37
|
+
_RUNTIME_OVERRIDES.update(overrides)
|
|
38
|
+
|
|
30
39
|
|
|
31
40
|
def get_config_dir() -> Path:
|
|
32
41
|
"""Ensure and return the user config directory (~/.config/aston/)."""
|
|
@@ -38,9 +47,14 @@ def get_config_dir() -> Path:
|
|
|
38
47
|
def load_config() -> dict:
|
|
39
48
|
"""
|
|
40
49
|
Load configuration from ~/.config/aston/config.yaml,
|
|
41
|
-
falling back to defaults
|
|
50
|
+
falling back to defaults, applying environment variable overrides,
|
|
51
|
+
and overlaying runtime CLI overrides.
|
|
42
52
|
"""
|
|
43
|
-
|
|
53
|
+
# Create a deep-ish copy of defaults to prevent mutating the global dictionary
|
|
54
|
+
config = {
|
|
55
|
+
section: values.copy() if isinstance(values, dict) else values
|
|
56
|
+
for section, values in DEFAULT_CONFIG.items()
|
|
57
|
+
}
|
|
44
58
|
|
|
45
59
|
if CONFIG_FILE.is_file():
|
|
46
60
|
try:
|
|
@@ -49,7 +63,7 @@ def load_config() -> dict:
|
|
|
49
63
|
if isinstance(user_config, dict):
|
|
50
64
|
# Deep merge user config into defaults
|
|
51
65
|
for section, values in user_config.items():
|
|
52
|
-
if section in config and isinstance(values, dict):
|
|
66
|
+
if section in config and isinstance(values, dict) and isinstance(config[section], dict):
|
|
53
67
|
config[section].update(values)
|
|
54
68
|
else:
|
|
55
69
|
config[section] = values
|
|
@@ -60,6 +74,14 @@ def load_config() -> dict:
|
|
|
60
74
|
if os.getenv("ASTON_MODEL"):
|
|
61
75
|
config["llm"]["model"] = os.getenv("ASTON_MODEL")
|
|
62
76
|
|
|
77
|
+
# Apply runtime CLI overrides on top
|
|
78
|
+
if _RUNTIME_OVERRIDES:
|
|
79
|
+
for section, values in _RUNTIME_OVERRIDES.items():
|
|
80
|
+
if section in config and isinstance(values, dict) and isinstance(config[section], dict):
|
|
81
|
+
config[section].update(values)
|
|
82
|
+
else:
|
|
83
|
+
config[section] = values
|
|
84
|
+
|
|
63
85
|
return config
|
|
64
86
|
|
|
65
87
|
|
|
@@ -328,17 +328,23 @@ Validate each candidate independently. Preserve source metadata and exact
|
|
|
328
328
|
version boundary values supplied by the caller. Do not invent evidence or URLs.
|
|
329
329
|
"""
|
|
330
330
|
try:
|
|
331
|
-
response = call_llm(
|
|
332
|
-
|
|
333
|
-
|
|
331
|
+
response = call_llm(
|
|
332
|
+
prompt=user_prompt,
|
|
333
|
+
provider=provider_name,
|
|
334
|
+
model=model_name,
|
|
335
|
+
temperature=temperature,
|
|
336
|
+
system_prompt=VALIDATOR_SYSTEM_PROMPT,
|
|
337
|
+
response_format=ValidatedRuleset
|
|
338
|
+
)
|
|
339
|
+
parsed = response
|
|
340
|
+
if parsed is None or not hasattr(parsed, "rules"):
|
|
334
341
|
warning("Validator returned no parsed result; preserving candidates as needs_review.")
|
|
335
342
|
return preserve_for_review(rules, "the validator returned no parsed result")
|
|
336
|
-
|
|
337
|
-
# omitted any input, preserve it for review instead of silently losing it.
|
|
343
|
+
|
|
338
344
|
unmatched = list(enumerate(rules))
|
|
339
345
|
matched_results: list[tuple[dict, dict]] = []
|
|
340
346
|
for validated_model in parsed.rules:
|
|
341
|
-
validated = validated_model.model_dump()
|
|
347
|
+
validated = validated_model.model_dump() if hasattr(validated_model, "model_dump") else dict(validated_model)
|
|
342
348
|
key = _candidate_key(validated)
|
|
343
349
|
match_index = next(
|
|
344
350
|
(i for i, (_, source) in enumerate(unmatched) if _candidate_key(source) == key),
|
|
@@ -741,16 +747,26 @@ def extract_rules(
|
|
|
741
747
|
f"Documentation chunk:\n{chunk_text}"
|
|
742
748
|
)
|
|
743
749
|
|
|
744
|
-
response = call_llm(
|
|
750
|
+
response = call_llm(
|
|
751
|
+
prompt=content,
|
|
752
|
+
provider=provider_name,
|
|
753
|
+
model=model_name,
|
|
754
|
+
temperature=temperature,
|
|
755
|
+
system_prompt=prompt,
|
|
756
|
+
response_format=MigrationRuleset
|
|
757
|
+
)
|
|
745
758
|
|
|
746
|
-
parsed = response
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
)
|
|
759
|
+
parsed = response
|
|
760
|
+
|
|
761
|
+
# Gracefully handle empty or unparsed chunks instead of raising an error
|
|
762
|
+
if parsed is None or not hasattr(parsed, "rules") or not parsed.rules:
|
|
763
|
+
info(f"Chunk {chunk_number + 1} returned no rules for {package}; skipping chunk.")
|
|
764
|
+
continue
|
|
765
|
+
|
|
751
766
|
normalized = normalize_rule_symbols(
|
|
752
|
-
[rule.model_dump() for rule in parsed.rules]
|
|
767
|
+
[rule.model_dump() if hasattr(rule, "model_dump") else dict(rule) for rule in parsed.rules]
|
|
753
768
|
)
|
|
769
|
+
|
|
754
770
|
for rule in normalized:
|
|
755
771
|
rule["package"] = package
|
|
756
772
|
source_url = rule.get("source_url")
|
|
@@ -10,7 +10,7 @@ class BaseLLMProvider(ABC):
|
|
|
10
10
|
|
|
11
11
|
class MistralProvider(BaseLLMProvider):
|
|
12
12
|
def generate(self, prompt: str, model: str, temperature: float = 0.0, system_prompt: str = None, response_format=None) -> str:
|
|
13
|
-
from mistralai import Mistral
|
|
13
|
+
from mistralai.client import Mistral
|
|
14
14
|
api_key = os.getenv("MISTRAL_API_KEY")
|
|
15
15
|
if not api_key:
|
|
16
16
|
raise LLMError(
|
|
@@ -140,7 +140,12 @@ class GoogleProvider(BaseLLMProvider):
|
|
|
140
140
|
contents=prompt,
|
|
141
141
|
config=types.GenerateContentConfig(**config_kwargs)
|
|
142
142
|
)
|
|
143
|
-
|
|
143
|
+
|
|
144
|
+
# If response_format is used and parsed object is available, return it directly
|
|
145
|
+
if response_format and hasattr(response, "parsed") and response.parsed is not None:
|
|
146
|
+
return response.parsed
|
|
147
|
+
|
|
148
|
+
return response.text.strip() if response.text else ""
|
|
144
149
|
except Exception as exc:
|
|
145
150
|
raise LLMError(
|
|
146
151
|
message="Google Gemini API generation failed.",
|
|
@@ -410,7 +410,7 @@ def run_for_repo(
|
|
|
410
410
|
passed_files: list,
|
|
411
411
|
failed_files: list,
|
|
412
412
|
max_tries: int,
|
|
413
|
-
|
|
413
|
+
docker_file_time
|
|
414
414
|
):
|
|
415
415
|
with open("repo_index.json", "r", encoding="utf-8") as f:
|
|
416
416
|
repo_index = json.load(f)
|
|
@@ -683,7 +683,7 @@ def run_for_repo(
|
|
|
683
683
|
str(candidate_path),
|
|
684
684
|
temp_req_path,
|
|
685
685
|
repo_root=root_path,
|
|
686
|
-
timeout=
|
|
686
|
+
timeout=docker_file_time
|
|
687
687
|
)
|
|
688
688
|
|
|
689
689
|
context_data = {
|
|
@@ -734,7 +734,7 @@ def run_for_repo(
|
|
|
734
734
|
temp_req_path=temp_req_path,
|
|
735
735
|
context_data=context_data,
|
|
736
736
|
root_path=root_path,
|
|
737
|
-
docker_time=
|
|
737
|
+
docker_time=docker_file_time,
|
|
738
738
|
initial_result=pr,
|
|
739
739
|
max_retries=max_tries,
|
|
740
740
|
passed_files=passed_files,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: astoncli
|
|
3
|
-
Version: 0.1
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: Automated Python repository migration CLI tool
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -38,6 +38,7 @@ https://github.com/user-attachments/assets/812a1990-13c3-4c45-8a8e-080f602c7a3f
|
|
|
38
38
|
|
|
39
39
|
### Automated dependency migration, from breaking-change detection to a verified pull request.
|
|
40
40
|
|
|
41
|
+

|
|
41
42
|

|
|
42
43
|

|
|
43
44
|

|
|
@@ -735,6 +736,17 @@ Instead of manually hunting down every affected API, you receive a **pull reques
|
|
|
735
736
|
|
|
736
737
|
## Installation
|
|
737
738
|
|
|
739
|
+
### From PyPI (recommended)
|
|
740
|
+
|
|
741
|
+
```bash
|
|
742
|
+
pip install astoncli
|
|
743
|
+
aston --help
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
The package is named `astoncli` on PyPI, and the command it installs is `aston`.
|
|
747
|
+
|
|
748
|
+
### From source
|
|
749
|
+
|
|
738
750
|
```bash
|
|
739
751
|
# 1. Clone
|
|
740
752
|
git clone https://github.com/2022n02511-stack/ASTon.git
|
|
@@ -752,6 +764,8 @@ aston --help
|
|
|
752
764
|
|
|
753
765
|
Then configure the environment variables required by your selected **LLM provider** and **GitHub integration**. A template is provided in `.env.example`.
|
|
754
766
|
|
|
767
|
+
> **External requirements:** Docker must be installed and running, and you need an API key for your LLM provider and a GitHub token for pull requests. Installing the package does not provide these.
|
|
768
|
+
|
|
755
769
|
---
|
|
756
770
|
|
|
757
771
|
## Design principles
|
|
@@ -782,7 +796,7 @@ The architecture separates ingestion, rule extraction, repository analysis, code
|
|
|
782
796
|
- [ ] Version-aware rule validation across more version chains (in progress)
|
|
783
797
|
- [ ] Reliability across more real-world repositories
|
|
784
798
|
- [ ] Support for additional Python packages
|
|
785
|
-
- [
|
|
799
|
+
- [x] `pip install astoncli` distribution
|
|
786
800
|
- [ ] Broader language ecosystem support
|
|
787
801
|
|
|
788
802
|
---
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "astoncli" # Available on PyPI, while your internal app and CLI command remain 'aston'
|
|
7
|
-
version = "0.1
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "Automated Python repository migration CLI tool"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
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
|