Compare commits
64 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b6d861d82 | |||
| 493164d147 | |||
| 343c9b288e | |||
| e3937ed2fe | |||
| 2952c7f83c | |||
| fa1d0b129b | |||
| ef5f6c8397 | |||
| 28ff68068a | |||
| 80ebe6fd65 | |||
| 3eab860187 | |||
| 25d64157e7 | |||
| e0a72c46ff | |||
| 24f7b449da | |||
| cc230adc64 | |||
| 4e0a97f26f | |||
| e68c6102b3 | |||
| cbf233be79 | |||
| 291a6402b9 | |||
| 98638bd994 | |||
| 30b097fdcb | |||
| 4577239526 | |||
| 8c9e14cbd0 | |||
| d8a75ea395 | |||
| 1ca990875f | |||
| 98f32b7d28 | |||
| 436932c9da | |||
| cecd162641 | |||
| c95c651486 | |||
| 970cb0fd41 | |||
| 9de791ebb0 | |||
| 996f69b4ca | |||
| dc49ede69d | |||
| 98e85d8ac8 | |||
| 90d2a85c83 | |||
| 8ac026f0c9 | |||
| 2095217d0f | |||
| c0ee2091f6 | |||
| 1085fbe3ee | |||
| 459737a1b0 | |||
| 228e2c981b | |||
| 08e451198b | |||
| d87f1004ab | |||
| d682bc5e18 | |||
| f507a005a8 | |||
| c72195fa33 | |||
| 1093cc76bb | |||
| eda78b6530 | |||
| b3b3a54b90 | |||
| e16fa6b3d2 | |||
| e88b92e69f | |||
| 9fdf1e5c78 | |||
| 045aa09784 | |||
| c36345b842 | |||
| f2104c5041 | |||
| d23a9d6153 | |||
| bb69623fc6 | |||
| 3cb46dc1bd | |||
| 249eeaf4d5 | |||
| 83bbd58728 | |||
| d5deb809c3 | |||
| c77a8681f7 | |||
| 0fe190a913 | |||
| 99156ade28 | |||
| 44ab0ba1ec |
@@ -2,44 +2,57 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
branches: [ main, master ]
|
||||
pull_request:
|
||||
branches: [main]
|
||||
branches: [ main, master ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
test:
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install linting tools
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install ruff mypy
|
||||
|
||||
- name: Run ruff check
|
||||
run: python -m ruff check config_convert tests
|
||||
|
||||
- name: Run ruff format check
|
||||
run: python -m ruff format --check config_convert tests
|
||||
|
||||
- name: Run mypy type checking
|
||||
run: python -m mypy config_convert tests
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install -e ".[dev]"
|
||||
|
||||
- name: Run tests
|
||||
run: pytest tests/ -v --tb=short
|
||||
|
||||
- name: Run tests with coverage
|
||||
run: pytest --cov=config_convert --cov-report=term-missing
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install lint tools
|
||||
run: pip install ruff
|
||||
|
||||
- name: Run ruff
|
||||
run: ruff check .
|
||||
|
||||
- name: Run pytest
|
||||
run: python -m pytest tests/ -v --tb=short --ignore=tests/integration/
|
||||
|
||||
153
README.md
153
README.md
@@ -1,6 +1,6 @@
|
||||
# ConfigConvert CLI
|
||||
|
||||
A powerful CLI tool for bidirectional conversion between JSON, YAML, TOML, and ENV config formats with smart type inference, validation, flatten/unflatten operations, schema generation, and automatic shell completion support.
|
||||
A powerful CLI tool for bidirectional conversion between JSON, YAML, TOML, and ENV config formats.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -11,25 +11,14 @@ A powerful CLI tool for bidirectional conversion between JSON, YAML, TOML, and E
|
||||
- **Schema Generation**: Generate JSON Schema from parsed configurations
|
||||
- **Shell Completion**: Built-in support for bash, zsh, and fish completions
|
||||
- **Offline Operation**: Runs entirely offline with minimal dependencies
|
||||
- **Rich Output**: Beautiful terminal output using Rich library
|
||||
|
||||
## Installation
|
||||
|
||||
### From PyPI
|
||||
|
||||
```bash
|
||||
pip install config-convert-cli
|
||||
```
|
||||
|
||||
### From Source
|
||||
|
||||
```bash
|
||||
git clone https://7000pct.gitea.bloupla.net/7000pctAUTO/config-convert-cli.git
|
||||
cd config-convert-cli
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
## Usage
|
||||
|
||||
### Convert between formats
|
||||
|
||||
@@ -37,77 +26,55 @@ pip install -e ".[dev]"
|
||||
# Convert JSON to YAML
|
||||
config-convert convert input.json --to yaml -o output.yaml
|
||||
|
||||
# Convert YAML to JSON with custom indentation
|
||||
config-convert convert config.yaml --from yaml --to json --indent 4
|
||||
# Convert YAML to JSON
|
||||
config-convert convert config.yaml --from yaml --to json
|
||||
|
||||
# Convert ENV to JSON
|
||||
config-convert convert .env --from env --to json
|
||||
|
||||
# Read from stdin
|
||||
cat config.json | config-convert convert --stdin --from json --to yaml
|
||||
|
||||
# Pretty print output
|
||||
config-convert convert config.json --to yaml --indent 2
|
||||
config-convert convert config.json --to yaml --pretty
|
||||
```
|
||||
|
||||
### Validate syntax
|
||||
|
||||
```bash
|
||||
# Validate a config file
|
||||
config-convert validate config.yaml
|
||||
|
||||
# Validate from stdin
|
||||
echo '{"name": "test"}' | config-convert validate --stdin --format json
|
||||
config-validate config.yaml
|
||||
```
|
||||
|
||||
### Flatten nested structures
|
||||
|
||||
```bash
|
||||
# Flatten nested JSON to ENV format
|
||||
config-convert flatten config.json --output flat.env
|
||||
|
||||
# Flatten to another structured format
|
||||
config-convert flatten config.json --format yaml
|
||||
```
|
||||
|
||||
### Unflatten to nested structures
|
||||
|
||||
```bash
|
||||
# Unflatten ENV to JSON
|
||||
config-convert unflatten flat.env --format json --output nested.json
|
||||
config-convert unflatten flat.env --output nested.yaml
|
||||
```
|
||||
|
||||
### Generate JSON Schema
|
||||
|
||||
```bash
|
||||
# Generate schema from config
|
||||
config-convert schema config.json -o schema.json
|
||||
|
||||
# Generate and display schema
|
||||
config-convert schema config.json
|
||||
```
|
||||
|
||||
### List supported formats
|
||||
|
||||
```bash
|
||||
config-convert formats
|
||||
```
|
||||
|
||||
## Supported Formats
|
||||
|
||||
| Format | Extensions | Read | Write |
|
||||
|--------|------------|------|-------|
|
||||
| JSON | .json | Yes | Yes |
|
||||
| YAML | .yaml, .yml| Yes | Yes |
|
||||
| TOML | .toml | Yes | Yes |
|
||||
| ENV | .env | Yes | Yes |
|
||||
| Format | Extension | Read | Write |
|
||||
|--------|-----------|------|-------|
|
||||
| JSON | .json | ✓ | ✓ |
|
||||
| YAML | .yaml | ✓ | ✓ |
|
||||
| TOML | .toml | ✓ | ✓ |
|
||||
| ENV | .env | ✓ | ✓ |
|
||||
|
||||
## Shell Completion
|
||||
|
||||
### Bash
|
||||
|
||||
```bash
|
||||
# Install completions for current user
|
||||
# Install completions
|
||||
config-convert --install-completion bash
|
||||
|
||||
# Or source directly
|
||||
@@ -126,95 +93,17 @@ config-convert --install-completion zsh
|
||||
config-convert --install-completion fish
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Default |
|
||||
|----------|-------------|---------|
|
||||
| CONFIG_CONVERT_THEME | Color theme for Rich output | default |
|
||||
| CONFIG_CONVERT_INDENT | Default indentation for output | 2 |
|
||||
|
||||
## Exit Codes
|
||||
|
||||
| Code | Description |
|
||||
|------|-------------|
|
||||
| 0 | Success |
|
||||
| 1 | General error |
|
||||
| 2 | Invalid arguments |
|
||||
| 3 | File not found |
|
||||
| 4 | Syntax error in input |
|
||||
| 5 | Conversion error |
|
||||
|
||||
## Development
|
||||
|
||||
### Setup
|
||||
|
||||
```bash
|
||||
# Create virtual environment
|
||||
python -m venv venv
|
||||
source venv/bin/activate # On Windows: venv\Scripts\activate
|
||||
|
||||
# Install dependencies
|
||||
pip install -e ".[dev]"
|
||||
|
||||
# Run tests
|
||||
pytest tests/ -v
|
||||
|
||||
# Run with coverage
|
||||
pytest --cov=config_convert --cov-report=term-missing
|
||||
|
||||
# Run linting
|
||||
ruff check .
|
||||
```
|
||||
|
||||
### Project Structure
|
||||
|
||||
```
|
||||
config-convert-cli/
|
||||
├── config_convert/
|
||||
│ ├── __init__.py
|
||||
│ ├── cli.py
|
||||
│ ├── converters/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── base.py
|
||||
│ │ ├── json_converter.py
|
||||
│ │ ├── yaml_converter.py
|
||||
│ │ ├── toml_converter.py
|
||||
│ │ └── env_converter.py
|
||||
│ ├── utils/
|
||||
│ │ ├── __init__.py
|
||||
│ │ ├── type_inference.py
|
||||
│ │ ├── flatten.py
|
||||
│ │ └── schema.py
|
||||
│ └── validators/
|
||||
│ ├── __init__.py
|
||||
│ └── syntax.py
|
||||
├── tests/
|
||||
│ ├── __init__.py
|
||||
│ ├── conftest.py
|
||||
│ ├── test_cli.py
|
||||
│ ├── test_converters/
|
||||
│ ├── test_type_inference.py
|
||||
│ ├── test_flatten.py
|
||||
│ ├── test_schema.py
|
||||
│ ├── test_validators.py
|
||||
│ └── fixtures/
|
||||
├── scripts/
|
||||
│ └── completions.py
|
||||
├── pyproject.toml
|
||||
├── requirements.txt
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
1. Fork the repository
|
||||
2. Create a feature branch
|
||||
3. Make your changes
|
||||
4. Run tests and linting
|
||||
5. Submit a pull request
|
||||
| 0 | Success |
|
||||
| 1 | General error |
|
||||
| 2 | Invalid arguments |
|
||||
| 3 | File not found |
|
||||
| 4 | Syntax error in input |
|
||||
| 5 | Conversion error |
|
||||
|
||||
## License
|
||||
|
||||
MIT License - see LICENSE file for details.
|
||||
MIT
|
||||
|
||||
1
app/config_convert/cli.py
Normal file
1
app/config_convert/cli.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/cli.py
|
||||
1
app/config_convert/converters/base.py
Normal file
1
app/config_convert/converters/base.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/converters/base.py
|
||||
1
app/config_convert/converters/env_converter.py
Normal file
1
app/config_convert/converters/env_converter.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/converters/env_converter.py
|
||||
1
app/config_convert/converters/json_converter.py
Normal file
1
app/config_convert/converters/json_converter.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/converters/json_converter.py
|
||||
1
app/config_convert/converters/toml_converter.py
Normal file
1
app/config_convert/converters/toml_converter.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/converters/toml_converter.py
|
||||
1
app/config_convert/converters/yaml_converter.py
Normal file
1
app/config_convert/converters/yaml_converter.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/converters/yaml_converter.py
|
||||
1
app/config_convert/utils/flatten.py
Normal file
1
app/config_convert/utils/flatten.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/utils/flatten.py
|
||||
1
app/config_convert/validators/__init__.py
Normal file
1
app/config_convert/validators/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/validators/__init__.py
|
||||
1
app/config_convert/validators/syntax.py
Normal file
1
app/config_convert/validators/syntax.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/config_convert/validators/syntax.py
|
||||
1
app/tests/conftest.py
Normal file
1
app/tests/conftest.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/conftest.py
|
||||
1
app/tests/integration/test_full_workflow.py
Normal file
1
app/tests/integration/test_full_workflow.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/integration/test_full_workflow.py
|
||||
1
app/tests/test_cli.py
Normal file
1
app/tests/test_cli.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_cli.py
|
||||
1
app/tests/test_converters/test_json.py
Normal file
1
app/tests/test_converters/test_json.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_converters/test_json.py
|
||||
1
app/tests/test_converters/test_toml.py
Normal file
1
app/tests/test_converters/test_toml.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_converters/test_toml.py
|
||||
1
app/tests/test_extractors.py
Normal file
1
app/tests/test_extractors.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_extractors.py
|
||||
1
app/tests/test_flatten.py
Normal file
1
app/tests/test_flatten.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_flatten.py
|
||||
1
app/tests/test_formatters.py
Normal file
1
app/tests/test_formatters.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_formatters.py
|
||||
1
app/tests/test_integration.py
Normal file
1
app/tests/test_integration.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_integration.py
|
||||
1
app/tests/test_schema.py
Normal file
1
app/tests/test_schema.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_schema.py
|
||||
1
app/tests/test_validators.py
Normal file
1
app/tests/test_validators.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/test_validators.py
|
||||
1
app/tests/unit/test_cli.py
Normal file
1
app/tests/unit/test_cli.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/unit/test_cli.py
|
||||
1
app/tests/unit/test_generators.py
Normal file
1
app/tests/unit/test_generators.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/unit/test_generators.py
|
||||
1
app/tests/unit/test_parsers.py
Normal file
1
app/tests/unit/test_parsers.py
Normal file
@@ -0,0 +1 @@
|
||||
/app/tests/unit/test_parsers.py
|
||||
@@ -7,7 +7,6 @@ from typing import Optional
|
||||
import typer
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
from rich.syntax import Syntax
|
||||
|
||||
from config_convert import __version__
|
||||
from config_convert.converters import (
|
||||
@@ -89,6 +88,7 @@ def convert(
|
||||
echo_error("Please specify --from when using --stdin")
|
||||
raise typer.Exit(2)
|
||||
else:
|
||||
assert input_file is not None
|
||||
fmt = from_format or get_format_from_path(input_file)
|
||||
data_str = Path(input_file).read_text(encoding="utf-8")
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Optional
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
from config_convert.converters.base import Converter
|
||||
from config_convert.utils.type_inference import convert_value
|
||||
|
||||
@@ -23,7 +23,7 @@ class TOMLConverter(Converter):
|
||||
return tomllib.loads(data)
|
||||
|
||||
def dumps(self, data: Dict[str, Any], indent: Optional[int] = None) -> str:
|
||||
output = []
|
||||
output: list = []
|
||||
self._write_dict(data, output, indent=0)
|
||||
return "\n".join(output)
|
||||
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
"""Utilities for flattening and unflattening nested dictionaries."""
|
||||
|
||||
import re
|
||||
from collections.abc import MutableMapping
|
||||
from typing import Any, Dict, List, Tuple
|
||||
from typing import Any, Dict, List
|
||||
|
||||
|
||||
def flatten_dict(data: Dict[str, Any], parent_key: str = "", sep: str = ".") -> Dict[str, Any]:
|
||||
@@ -104,7 +102,6 @@ def _split_key(key: str, sep: str) -> List[str]:
|
||||
def _set_nested(d: Any, parts: List[str], value: Any) -> None:
|
||||
"""Set a value in a nested structure, creating intermediate dicts or lists as needed."""
|
||||
current = d
|
||||
path = [] # Track the path to enable modification at the right level
|
||||
|
||||
for i, part in enumerate(parts[:-1]):
|
||||
if isinstance(current, list):
|
||||
@@ -137,7 +134,7 @@ def _set_nested(d: Any, parts: List[str], value: Any) -> None:
|
||||
current[part] = {}
|
||||
current = current[part]
|
||||
else:
|
||||
raise ValueError(f"Cannot traverse through non-dict/list object")
|
||||
raise ValueError("Cannot traverse through non-dict/list object")
|
||||
|
||||
last_part = parts[-1]
|
||||
if isinstance(current, list):
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"""JSON Schema generation from parsed configurations."""
|
||||
|
||||
from typing import Any, Dict, List, Union
|
||||
from typing import Any, Dict
|
||||
|
||||
|
||||
def generate_schema(data: Any) -> Dict[str, Any]:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
"""Smart type inference utilities for converting string values to Python types."""
|
||||
|
||||
import re
|
||||
from typing import Any, Optional, Union
|
||||
from typing import Any
|
||||
|
||||
|
||||
BOOLEAN_TRUE_VALUES = {"true", "yes", "on", "1"}
|
||||
|
||||
@@ -2,8 +2,7 @@
|
||||
|
||||
import json
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import Any, Optional, Tuple
|
||||
from typing import Optional, Tuple
|
||||
|
||||
import yaml
|
||||
|
||||
@@ -104,9 +103,9 @@ def validate_env(data: str) -> Tuple[bool, Optional[ValidationError]]:
|
||||
if not stripped or stripped.startswith("#"):
|
||||
continue
|
||||
if not line.strip() == line:
|
||||
return False, ValidationError(f"Invalid KEY=value format", line_num)
|
||||
return False, ValidationError("Invalid KEY=value format", line_num)
|
||||
if not ENV_LINE_PATTERN.match(line):
|
||||
return False, ValidationError(f"Invalid KEY=value format", line_num)
|
||||
return False, ValidationError("Invalid KEY=value format", line_num)
|
||||
return True, None
|
||||
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ dependencies = [
|
||||
dev = [
|
||||
"pytest>=7.4.0",
|
||||
"pytest-cov>=4.1.0",
|
||||
"ruff>=0.4.0",
|
||||
"mypy>=1.10.0",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
"""Tests package."""
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
@@ -24,43 +23,43 @@ def sample_json():
|
||||
@pytest.fixture
|
||||
def sample_yaml():
|
||||
return """name: test-project
|
||||
version: '1.0.0'
|
||||
debug: true
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
ssl: false
|
||||
tags:
|
||||
- python
|
||||
- cli
|
||||
"""
|
||||
version: '1.0.0'
|
||||
debug: true
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
ssl: false
|
||||
tags:
|
||||
- python
|
||||
- cli
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_toml():
|
||||
return """name = "test-project"
|
||||
version = "1.0.0"
|
||||
debug = true
|
||||
|
||||
[database]
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
ssl = false
|
||||
|
||||
tags = ["python", "cli"]
|
||||
"""
|
||||
version = "1.0.0"
|
||||
debug = true
|
||||
|
||||
[database]
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
ssl = false
|
||||
|
||||
tags = ["python", "cli"]
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_env():
|
||||
return """NAME=test-project
|
||||
VERSION=1.0.0
|
||||
DEBUG=true
|
||||
DATABASE_HOST=localhost
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_SSL=false
|
||||
TAGS=python,cli
|
||||
"""
|
||||
VERSION=1.0.0
|
||||
DEBUG=true
|
||||
DATABASE_HOST=localhost
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_SSL=false
|
||||
TAGS=python,cli
|
||||
"""
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
|
||||
1
tests/fixtures/__init__.py
vendored
1
tests/fixtures/__init__.py
vendored
@@ -1 +1,2 @@
|
||||
"""Test fixtures package."""
|
||||
|
||||
|
||||
50
tests/fixtures/sample_files.py
vendored
50
tests/fixtures/sample_files.py
vendored
@@ -10,38 +10,38 @@ SAMPLE_JSON = """{
|
||||
"ssl": false
|
||||
},
|
||||
"tags": ["python", "cli"]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
SAMPLE_YAML = """name: test-project
|
||||
version: '1.0.0'
|
||||
debug: true
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
ssl: false
|
||||
tags:
|
||||
- python
|
||||
- cli
|
||||
version: '1.0.0'
|
||||
debug: true
|
||||
database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
ssl: false
|
||||
tags:
|
||||
- python
|
||||
- cli
|
||||
"""
|
||||
|
||||
SAMPLE_TOML = """name = "test-project"
|
||||
version = "1.0.0"
|
||||
debug = true
|
||||
|
||||
[database]
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
ssl = false
|
||||
|
||||
tags = ["python", "cli"]
|
||||
version = "1.0.0"
|
||||
debug = true
|
||||
|
||||
[database]
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
ssl = false
|
||||
|
||||
tags = ["python", "cli"]
|
||||
"""
|
||||
|
||||
SAMPLE_ENV = """NAME=test-project
|
||||
VERSION=1.0.0
|
||||
DEBUG=true
|
||||
DATABASE_HOST=localhost
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_SSL=false
|
||||
TAGS=python,cli
|
||||
VERSION=1.0.0
|
||||
DEBUG=true
|
||||
DATABASE_HOST=localhost
|
||||
DATABASE_PORT=5432
|
||||
DATABASE_SSL=false
|
||||
TAGS=python,cli
|
||||
"""
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import pytest
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typer.testing import CliRunner
|
||||
|
||||
from config_convert.cli import app
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
"""Converters tests package."""
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from config_convert.converters import ENVConverter
|
||||
|
||||
@@ -97,7 +96,6 @@ class TestENVConverter:
|
||||
os.unlink(path)
|
||||
|
||||
def test_dump_file(self, converter, temp_dir, sample_env):
|
||||
import shutil
|
||||
path = tempfile.mktemp(suffix=".env")
|
||||
try:
|
||||
data = converter.loads(sample_env)
|
||||
@@ -105,7 +103,7 @@ class TestENVConverter:
|
||||
result = converter.load(path)
|
||||
assert result == data
|
||||
finally:
|
||||
if Path(path).exists():
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
|
||||
def test_invalid_env_raises(self, converter):
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
"""Tests for JSON converter."""
|
||||
|
||||
import pytest
|
||||
import json
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from config_convert.converters import JSONConverter
|
||||
|
||||
@@ -63,14 +62,13 @@ class TestJSONConverter:
|
||||
os.unlink(path)
|
||||
|
||||
def test_dump_file(self, converter, temp_dir, sample_json):
|
||||
import shutil
|
||||
path = tempfile.mktemp(suffix=".json")
|
||||
try:
|
||||
converter.dump(sample_json, path)
|
||||
result = json.loads(Path(path).read_text())
|
||||
result = json.loads(open(path).read())
|
||||
assert result == sample_json
|
||||
finally:
|
||||
if Path(path).exists():
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
|
||||
def test_invalid_json_raises(self, converter):
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
from config_convert.converters import TOMLConverter
|
||||
@@ -21,9 +20,9 @@ class TestTOMLConverter:
|
||||
|
||||
def test_loads_nested_toml(self, converter):
|
||||
data = """[database]
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
"""
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
"""
|
||||
result = converter.loads(data)
|
||||
assert result == {"database": {"host": "localhost", "port": 5432}}
|
||||
|
||||
@@ -63,7 +62,6 @@ class TestTOMLConverter:
|
||||
os.unlink(path)
|
||||
|
||||
def test_dump_file(self, converter, temp_dir, sample_toml):
|
||||
import shutil
|
||||
path = tempfile.mktemp(suffix=".toml")
|
||||
try:
|
||||
if sys.version_info >= (3, 11):
|
||||
@@ -75,7 +73,7 @@ class TestTOMLConverter:
|
||||
result = converter.load(path)
|
||||
assert result == data
|
||||
finally:
|
||||
if Path(path).exists():
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
|
||||
def test_invalid_toml_raises(self, converter):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import pytest
|
||||
import tempfile
|
||||
import os
|
||||
from pathlib import Path
|
||||
import yaml
|
||||
|
||||
from config_convert.converters import YAMLConverter
|
||||
|
||||
@@ -20,9 +20,9 @@ class TestYAMLConverter:
|
||||
|
||||
def test_loads_nested_yaml(self, converter):
|
||||
data = """database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
"""
|
||||
host: localhost
|
||||
port: 5432
|
||||
"""
|
||||
result = converter.loads(data)
|
||||
assert result == {"database": {"host": "localhost", "port": 5432}}
|
||||
|
||||
@@ -33,9 +33,9 @@ class TestYAMLConverter:
|
||||
|
||||
def test_loads_multiline_string(self, converter):
|
||||
data = """description: |
|
||||
This is a
|
||||
multiline string
|
||||
"""
|
||||
This is a
|
||||
multiline string
|
||||
"""
|
||||
result = converter.loads(data)
|
||||
assert result["description"] == "This is a\nmultiline string\n"
|
||||
|
||||
@@ -56,7 +56,6 @@ class TestYAMLConverter:
|
||||
assert loaded == original
|
||||
|
||||
def test_load_file(self, converter, temp_file, sample_yaml):
|
||||
import yaml
|
||||
gen = temp_file(sample_yaml, suffix=".yaml")
|
||||
path = next(gen)
|
||||
try:
|
||||
@@ -66,8 +65,6 @@ class TestYAMLConverter:
|
||||
os.unlink(path)
|
||||
|
||||
def test_dump_file(self, converter, temp_dir, sample_yaml):
|
||||
import yaml
|
||||
import shutil
|
||||
path = tempfile.mktemp(suffix=".yaml")
|
||||
try:
|
||||
data = yaml.safe_load(sample_yaml)
|
||||
@@ -75,7 +72,7 @@ class TestYAMLConverter:
|
||||
result = converter.load(path)
|
||||
assert result == data
|
||||
finally:
|
||||
if Path(path).exists():
|
||||
if os.path.exists(path):
|
||||
os.unlink(path)
|
||||
|
||||
def test_invalid_yaml_raises(self, converter):
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"""Tests for JSON Schema generation."""
|
||||
|
||||
import pytest
|
||||
|
||||
from config_convert.utils import generate_schema
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"""Tests for type inference module."""
|
||||
|
||||
import pytest
|
||||
|
||||
from config_convert.utils import detect_type, convert_value, infer_types
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
"""Tests for syntax validation."""
|
||||
|
||||
import pytest
|
||||
|
||||
from config_convert.validators import validate
|
||||
|
||||
|
||||
@@ -12,7 +10,7 @@ class TestValidateJSON:
|
||||
assert error is None
|
||||
|
||||
def test_valid_json_pretty(self):
|
||||
is_valid, error = validate('{\n "name": "test\n"}', "json")
|
||||
is_valid, error = validate('{\n "name": "test"\n}', "json")
|
||||
assert is_valid is True
|
||||
|
||||
def test_invalid_json(self):
|
||||
@@ -33,9 +31,9 @@ class TestValidateYAML:
|
||||
|
||||
def test_valid_yaml_nested(self):
|
||||
data = """database:
|
||||
host: localhost
|
||||
port: 5432
|
||||
"""
|
||||
host: localhost
|
||||
port: 5432
|
||||
"""
|
||||
is_valid, error = validate(data, "yaml")
|
||||
assert is_valid is True
|
||||
|
||||
@@ -53,9 +51,9 @@ class TestValidateTOML:
|
||||
|
||||
def test_valid_toml_nested(self):
|
||||
data = """[database]
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
"""
|
||||
host = "localhost"
|
||||
port = 5432
|
||||
"""
|
||||
is_valid, error = validate(data, "toml")
|
||||
assert is_valid is True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user