init
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@ -8,3 +8,4 @@ wheels/
|
||||
|
||||
# Virtual environments
|
||||
.venv
|
||||
examples/*.json
|
||||
|
||||
142
README.md
142
README.md
@ -1,39 +1,119 @@
|
||||
# zig-fetch-py
|
||||
|
||||
A Python tool to parse Zig Object Notation (ZON) files and convert them to JSON.
|
||||
|
||||
## Installation
|
||||
|
||||
### Using uv (recommended)
|
||||
|
||||
[uv](https://github.com/astral-sh/uv) is a fast Python package installer and resolver. To install zig-fetch-py using uv:
|
||||
|
||||
```bash
|
||||
# Install uv if you don't have it
|
||||
curl -sSf https://astral.sh/uv/install.sh | bash
|
||||
|
||||
# Create and activate a virtual environment
|
||||
uv venv
|
||||
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
||||
|
||||
# Install the package in development mode
|
||||
uv pip install -e .
|
||||
|
||||
# Install development dependencies
|
||||
uv pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
### Using pip
|
||||
|
||||
```bash
|
||||
# Create and activate a virtual environment
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # On Windows: .venv\Scripts\activate
|
||||
|
||||
# Install the package in development mode
|
||||
pip install -e .
|
||||
|
||||
# Install development dependencies
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Command Line
|
||||
|
||||
```bash
|
||||
# Basic usage
|
||||
zon2json path/to/file.zon
|
||||
|
||||
# Output to a file
|
||||
zon2json path/to/file.zon -o output.json
|
||||
|
||||
# Pretty print the JSON
|
||||
zon2json path/to/file.zon -p
|
||||
|
||||
# Enable verbose logging
|
||||
zon2json path/to/file.zon -v
|
||||
```
|
||||
|
||||
### Python API
|
||||
|
||||
```python
|
||||
from zig_fetch_py.parser import parse_zon_file, zon_to_json
|
||||
|
||||
# Parse a ZON file
|
||||
result = parse_zon_file("path/to/file.zon")
|
||||
print(result) # Python dictionary
|
||||
|
||||
# Convert ZON content to JSON
|
||||
zon_content = """.{
|
||||
.name = "test",
|
||||
.version = "1.0.0",
|
||||
}"""
|
||||
json_str = zon_to_json(zon_content, indent=4)
|
||||
print(json_str)
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Run all tests
|
||||
pytest
|
||||
|
||||
# Run tests with coverage
|
||||
pytest --cov=zig_fetch_py
|
||||
|
||||
# Generate coverage report
|
||||
pytest --cov=zig_fetch_py --cov-report=html
|
||||
```
|
||||
|
||||
## ZON Format
|
||||
|
||||
Zig Object Notation (ZON) is a data format used by the Zig programming language. It's similar to JSON but with some differences in syntax:
|
||||
|
||||
- Objects are defined with `.{ ... }`
|
||||
- Keys are prefixed with a dot: `.key = value`
|
||||
- Arrays are defined with `.[ ... ]`
|
||||
- Special identifiers can be quoted with `@`: `.@"special-name" = value`
|
||||
- Comments use `//` syntax
|
||||
|
||||
Example:
|
||||
|
||||
```zon
|
||||
.{
|
||||
.name = .zls,
|
||||
// Must match the `zls_version` in `build.zig`
|
||||
.version = "0.15.0-dev",
|
||||
// Must be kept in line with the `minimum_build_zig_version` in `build.zig`.
|
||||
// Should be a Zig version that is downloadable from https://ziglang.org/download/ or a mirror.
|
||||
.minimum_zig_version = "0.14.0",
|
||||
// If you do not use Nix, a ZLS maintainer can take care of this.
|
||||
// Whenever the dependencies are updated, run the following command:
|
||||
// ```bash
|
||||
// nix run github:Cloudef/zig2nix#zon2nix -- build.zig.zon > deps.nix
|
||||
// rm build.zig.zon2json-lock # this file is unnecessary
|
||||
// ```
|
||||
.name = "example",
|
||||
.version = "1.0.0",
|
||||
.dependencies = .{
|
||||
.known_folders = .{
|
||||
.url = "https://github.com/ziglibs/known-folders/archive/aa24df42183ad415d10bc0a33e6238c437fc0f59.tar.gz",
|
||||
.hash = "known_folders-0.0.0-Fy-PJtLDAADGDOwYwMkVydMSTp_aN-nfjCZw6qPQ2ECL",
|
||||
},
|
||||
.diffz = .{
|
||||
.url = "https://github.com/ziglibs/diffz/archive/ef45c00d655e5e40faf35afbbde81a1fa5ed7ffb.tar.gz",
|
||||
.hash = "N-V-__8AABhrAQAQLLLGadghhPsdxTgBk9N9aLVOjXW3ay0V",
|
||||
},
|
||||
.@"lsp-codegen" = .{
|
||||
.url = "https://github.com/zigtools/zig-lsp-codegen/archive/063a98c13a2293d8654086140813bdd1de6501bc.tar.gz",
|
||||
.hash = "lsp_codegen-0.1.0-CMjjo0ZXCQB-rAhPYrlfzzpU0u0u2MeGvUucZ-_g32eg",
|
||||
},
|
||||
.tracy = .{
|
||||
.url = "https://github.com/wolfpld/tracy/archive/refs/tags/v0.11.1.tar.gz",
|
||||
.hash = "N-V-__8AAMeOlQEipHjcyu0TCftdAi9AQe7EXUDJOoVe0k-t",
|
||||
.lazy = true,
|
||||
.lib1 = .{
|
||||
.url = "https://example.com/lib1.tar.gz",
|
||||
.hash = "abcdef123456",
|
||||
},
|
||||
},
|
||||
.paths = .{""},
|
||||
.fingerprint = 0xa66330b97eb969ae, // Changing this has security and trust implications.
|
||||
.tags = .["tag1", "tag2"],
|
||||
}
|
||||
```
|
||||
|
||||
It's called `zon`, the Zig Object Notation. I think You need to parse it first (convert to json) and then parse the json.
|
||||
## License
|
||||
|
||||
MIT
|
||||
11
examples/example.zon
Normal file
11
examples/example.zon
Normal file
@ -0,0 +1,11 @@
|
||||
.{
|
||||
.name = "example",
|
||||
.version = "1.0.0",
|
||||
.dependencies = .{
|
||||
.lib1 = .{
|
||||
.url = "https://example.com/lib1.tar.gz",
|
||||
.hash = "abcdef123456",
|
||||
},
|
||||
},
|
||||
.tags = .["tag1", "tag2"],
|
||||
}
|
||||
64
examples/simple_example.py
Executable file
64
examples/simple_example.py
Executable file
@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simple example demonstrating how to use the zig-fetch-py library.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from loguru import logger
|
||||
from zig_fetch_py.parser import parse_zon_file, zon_to_json
|
||||
|
||||
# Configure logging
|
||||
logger.remove()
|
||||
logger.add(sys.stderr, level="INFO")
|
||||
|
||||
# Example ZON content
|
||||
ZON_CONTENT = """.{
|
||||
.name = "example",
|
||||
.version = "1.0.0",
|
||||
.dependencies = .{
|
||||
.lib1 = .{
|
||||
.url = "https://example.com/lib1.tar.gz",
|
||||
.hash = "abcdef123456",
|
||||
},
|
||||
},
|
||||
.tags = .["tag1", "tag2"],
|
||||
}"""
|
||||
|
||||
|
||||
def main():
|
||||
# Create a temporary ZON file
|
||||
example_dir = Path(__file__).parent
|
||||
zon_file = example_dir / "example.zon"
|
||||
zon_file.write_text(ZON_CONTENT)
|
||||
|
||||
logger.info(f"Created example ZON file: {zon_file}")
|
||||
|
||||
# Parse the ZON file
|
||||
result = parse_zon_file(str(zon_file))
|
||||
logger.info("Parsed ZON file to Python dictionary:")
|
||||
logger.info(result)
|
||||
|
||||
# Convert to JSON
|
||||
json_str = zon_to_json(ZON_CONTENT, indent=2)
|
||||
logger.info("Converted ZON to JSON:")
|
||||
logger.info(json_str)
|
||||
|
||||
# Save JSON to file
|
||||
json_file = example_dir / "example.json"
|
||||
with open(json_file, "w") as f:
|
||||
f.write(json_str)
|
||||
|
||||
logger.info(f"Saved JSON to file: {json_file}")
|
||||
|
||||
# Access specific values from the parsed data
|
||||
logger.info(f"Package name: {result['name']}")
|
||||
logger.info(f"Package version: {result['version']}")
|
||||
logger.info(f"Dependencies: {list(result['dependencies'].keys())}")
|
||||
logger.info(f"Tags: {result['tags']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@ -4,10 +4,7 @@ version = "0.1.0"
|
||||
description = "A tool to parse Zig Object Notation (ZON) files and convert them to JSON"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"click>=8.1.8",
|
||||
"loguru>=0.7.3",
|
||||
]
|
||||
dependencies = ["click>=8.1.8", "loguru>=0.7.3"]
|
||||
|
||||
[project.scripts]
|
||||
zon2json = "zig_fetch_py.main:main"
|
||||
@ -19,5 +16,14 @@ build-backend = "hatchling.build"
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["zig_fetch_py"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
python_files = "test_*.py"
|
||||
python_functions = "test_*"
|
||||
python_classes = "Test*"
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
|
||||
[project.optional-dependencies]
|
||||
dev = ["pytest>=8.3.5", "pytest-cov>=6.0.0"]
|
||||
|
||||
189
tests/test_parser.py
Normal file
189
tests/test_parser.py
Normal file
@ -0,0 +1,189 @@
|
||||
"""
|
||||
Unit tests for the ZON parser.
|
||||
"""
|
||||
|
||||
import json
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
|
||||
from zig_fetch_py.parser import ZonParser, parse_zon_file, zon_to_json
|
||||
|
||||
|
||||
class TestZonParser:
|
||||
"""Test cases for the ZonParser class."""
|
||||
|
||||
def test_parse_empty_object(self):
|
||||
"""Test parsing an empty object."""
|
||||
parser = ZonParser(".{}")
|
||||
result = parser.parse()
|
||||
assert result == {}
|
||||
|
||||
def test_parse_simple_object(self):
|
||||
"""Test parsing a simple object with string values."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.name = "test",
|
||||
.version = "1.0.0",
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"name": "test", "version": "1.0.0"}
|
||||
|
||||
def test_parse_nested_object(self):
|
||||
"""Test parsing a nested object."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.metadata = .{
|
||||
.name = "test",
|
||||
.version = "1.0.0",
|
||||
},
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"metadata": {"name": "test", "version": "1.0.0"}}
|
||||
|
||||
def test_parse_array(self):
|
||||
"""Test parsing an array."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.tags = .["tag1", "tag2", "tag3"],
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"tags": ["tag1", "tag2", "tag3"]}
|
||||
|
||||
def test_parse_numbers(self):
|
||||
"""Test parsing different number formats."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.integer = 42,
|
||||
.negative = -10,
|
||||
.float = 3.14,
|
||||
.hex = 0xDEADBEEF,
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {
|
||||
"integer": 42,
|
||||
"negative": -10,
|
||||
"float": 3.14,
|
||||
"hex": 0xDEADBEEF,
|
||||
}
|
||||
|
||||
def test_parse_boolean(self):
|
||||
"""Test parsing boolean values."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.is_true = true,
|
||||
.is_false = false,
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"is_true": True, "is_false": False}
|
||||
|
||||
def test_parse_null(self):
|
||||
"""Test parsing null values."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.nothing = null,
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"nothing": None}
|
||||
|
||||
def test_parse_comments(self):
|
||||
"""Test parsing with comments."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
// This is a comment
|
||||
.name = "test", // Inline comment
|
||||
// Another comment
|
||||
.version = "1.0.0",
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"name": "test", "version": "1.0.0"}
|
||||
|
||||
def test_parse_special_identifiers(self):
|
||||
"""Test parsing special identifiers with @ symbol."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.@"special-name" = "value",
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"special-name": "value"}
|
||||
|
||||
def test_parse_shorthand_notation(self):
|
||||
"""Test parsing shorthand notation where key is the same as value."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.name,
|
||||
.version,
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"name": "name", "version": "version"}
|
||||
|
||||
def test_parse_escaped_strings(self):
|
||||
"""Test parsing strings with escape sequences."""
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.escaped = "Line 1\\nLine 2\\tTabbed\\r\\n",
|
||||
}"""
|
||||
)
|
||||
result = parser.parse()
|
||||
assert result == {"escaped": "Line 1\nLine 2\tTabbed\r\n"}
|
||||
|
||||
def test_parse_error_invalid_syntax(self):
|
||||
"""Test that parser raises an error for invalid syntax."""
|
||||
with pytest.raises(ValueError):
|
||||
parser = ZonParser(".{,}")
|
||||
parser.parse()
|
||||
|
||||
def test_parse_error_unterminated_string(self):
|
||||
"""Test that parser raises an error for unterminated strings."""
|
||||
with pytest.raises(ValueError):
|
||||
parser = ZonParser(
|
||||
""".{
|
||||
.name = "unterminated,
|
||||
}"""
|
||||
)
|
||||
parser.parse()
|
||||
|
||||
|
||||
class TestZonFileParser:
|
||||
"""Test cases for the file parsing functions."""
|
||||
|
||||
def test_zon_to_json(self, tmp_path):
|
||||
"""Test converting ZON to JSON."""
|
||||
zon_content = """.{
|
||||
.name = "test",
|
||||
.version = "1.0.0",
|
||||
}"""
|
||||
|
||||
# Test without indentation
|
||||
json_str = zon_to_json(zon_content)
|
||||
parsed_json = json.loads(json_str)
|
||||
assert parsed_json == {"name": "test", "version": "1.0.0"}
|
||||
|
||||
# Test with indentation
|
||||
json_str_pretty = zon_to_json(zon_content, indent=2)
|
||||
assert " " in json_str_pretty # Should have indentation
|
||||
parsed_json = json.loads(json_str_pretty)
|
||||
assert parsed_json == {"name": "test", "version": "1.0.0"}
|
||||
|
||||
def test_parse_zon_file(self, tmp_path):
|
||||
"""Test parsing a ZON file."""
|
||||
# Create a temporary ZON file
|
||||
zon_file = tmp_path / "test.zon"
|
||||
zon_file.write_text(
|
||||
""".{
|
||||
.name = "test",
|
||||
.version = "1.0.0",
|
||||
}"""
|
||||
)
|
||||
|
||||
# Parse the file
|
||||
result = parse_zon_file(str(zon_file))
|
||||
assert result == {"name": "test", "version": "1.0.0"}
|
||||
103
uv.lock
generated
103
uv.lock
generated
@ -23,6 +23,54 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coverage"
|
||||
version = "7.6.12"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0c/d6/2b53ab3ee99f2262e6f0b8369a43f6d66658eab45510331c0b3d5c8c4272/coverage-7.6.12.tar.gz", hash = "sha256:48cfc4641d95d34766ad41d9573cc0f22a48aa88d22657a1fe01dca0dbae4de2", size = 805941 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/7f/4af2ed1d06ce6bee7eafc03b2ef748b14132b0bdae04388e451e4b2c529b/coverage-7.6.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b172f8e030e8ef247b3104902cc671e20df80163b60a203653150d2fc204d1ad", size = 208645 },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/60/d19df912989117caa95123524d26fc973f56dc14aecdec5ccd7d0084e131/coverage-7.6.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:641dfe0ab73deb7069fb972d4d9725bf11c239c309ce694dd50b1473c0f641c3", size = 208898 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/10/fecabcf438ba676f706bf90186ccf6ff9f6158cc494286965c76e58742fa/coverage-7.6.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e549f54ac5f301e8e04c569dfdb907f7be71b06b88b5063ce9d6953d2d58574", size = 242987 },
|
||||
{ url = "https://files.pythonhosted.org/packages/4c/53/4e208440389e8ea936f5f2b0762dcd4cb03281a7722def8e2bf9dc9c3d68/coverage-7.6.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:959244a17184515f8c52dcb65fb662808767c0bd233c1d8a166e7cf74c9ea985", size = 239881 },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/47/2ba744af8d2f0caa1f17e7746147e34dfc5f811fb65fc153153722d58835/coverage-7.6.12-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bda1c5f347550c359f841d6614fb8ca42ae5cb0b74d39f8a1e204815ebe25750", size = 242142 },
|
||||
{ url = "https://files.pythonhosted.org/packages/e9/90/df726af8ee74d92ee7e3bf113bf101ea4315d71508952bd21abc3fae471e/coverage-7.6.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1ceeb90c3eda1f2d8c4c578c14167dbd8c674ecd7d38e45647543f19839dd6ea", size = 241437 },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/af/995263fd04ae5f9cf12521150295bf03b6ba940d0aea97953bb4a6db3e2b/coverage-7.6.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f16f44025c06792e0fb09571ae454bcc7a3ec75eeb3c36b025eccf501b1a4c3", size = 239724 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/8e/5bb04f0318805e190984c6ce106b4c3968a9562a400180e549855d8211bd/coverage-7.6.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b076e625396e787448d27a411aefff867db2bffac8ed04e8f7056b07024eed5a", size = 241329 },
|
||||
{ url = "https://files.pythonhosted.org/packages/9e/9d/fa04d9e6c3f6459f4e0b231925277cfc33d72dfab7fa19c312c03e59da99/coverage-7.6.12-cp312-cp312-win32.whl", hash = "sha256:00b2086892cf06c7c2d74983c9595dc511acca00665480b3ddff749ec4fb2a95", size = 211289 },
|
||||
{ url = "https://files.pythonhosted.org/packages/53/40/53c7ffe3c0c3fff4d708bc99e65f3d78c129110d6629736faf2dbd60ad57/coverage-7.6.12-cp312-cp312-win_amd64.whl", hash = "sha256:7ae6eabf519bc7871ce117fb18bf14e0e343eeb96c377667e3e5dd12095e0288", size = 212079 },
|
||||
{ url = "https://files.pythonhosted.org/packages/76/89/1adf3e634753c0de3dad2f02aac1e73dba58bc5a3a914ac94a25b2ef418f/coverage-7.6.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:488c27b3db0ebee97a830e6b5a3ea930c4a6e2c07f27a5e67e1b3532e76b9ef1", size = 208673 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ce/64/92a4e239d64d798535c5b45baac6b891c205a8a2e7c9cc8590ad386693dc/coverage-7.6.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5d1095bbee1851269f79fd8e0c9b5544e4c00c0c24965e66d8cba2eb5bb535fd", size = 208945 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/d0/4596a3ef3bca20a94539c9b1e10fd250225d1dec57ea78b0867a1cf9742e/coverage-7.6.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0533adc29adf6a69c1baa88c3d7dbcaadcffa21afbed3ca7a225a440e4744bf9", size = 242484 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/ef/6fd0d344695af6718a38d0861408af48a709327335486a7ad7e85936dc6e/coverage-7.6.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53c56358d470fa507a2b6e67a68fd002364d23c83741dbc4c2e0680d80ca227e", size = 239525 },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/4b/373be2be7dd42f2bcd6964059fd8fa307d265a29d2b9bcf1d044bcc156ed/coverage-7.6.12-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64cbb1a3027c79ca6310bf101014614f6e6e18c226474606cf725238cf5bc2d4", size = 241545 },
|
||||
{ url = "https://files.pythonhosted.org/packages/a6/7d/0e83cc2673a7790650851ee92f72a343827ecaaea07960587c8f442b5cd3/coverage-7.6.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79cac3390bfa9836bb795be377395f28410811c9066bc4eefd8015258a7578c6", size = 241179 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/8c/566ea92ce2bb7627b0900124e24a99f9244b6c8c92d09ff9f7633eb7c3c8/coverage-7.6.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9b148068e881faa26d878ff63e79650e208e95cf1c22bd3f77c3ca7b1d9821a3", size = 239288 },
|
||||
{ url = "https://files.pythonhosted.org/packages/7d/e4/869a138e50b622f796782d642c15fb5f25a5870c6d0059a663667a201638/coverage-7.6.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8bec2ac5da793c2685ce5319ca9bcf4eee683b8a1679051f8e6ec04c4f2fd7dc", size = 241032 },
|
||||
{ url = "https://files.pythonhosted.org/packages/ae/28/a52ff5d62a9f9e9fe9c4f17759b98632edd3a3489fce70154c7d66054dd3/coverage-7.6.12-cp313-cp313-win32.whl", hash = "sha256:200e10beb6ddd7c3ded322a4186313d5ca9e63e33d8fab4faa67ef46d3460af3", size = 211315 },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/17/ab849b7429a639f9722fa5628364c28d675c7ff37ebc3268fe9840dda13c/coverage-7.6.12-cp313-cp313-win_amd64.whl", hash = "sha256:2b996819ced9f7dbb812c701485d58f261bef08f9b85304d41219b1496b591ef", size = 212099 },
|
||||
{ url = "https://files.pythonhosted.org/packages/d2/1c/b9965bf23e171d98505eb5eb4fb4d05c44efd256f2e0f19ad1ba8c3f54b0/coverage-7.6.12-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:299cf973a7abff87a30609879c10df0b3bfc33d021e1adabc29138a48888841e", size = 209511 },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/b3/119c201d3b692d5e17784fee876a9a78e1b3051327de2709392962877ca8/coverage-7.6.12-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:4b467a8c56974bf06e543e69ad803c6865249d7a5ccf6980457ed2bc50312703", size = 209729 },
|
||||
{ url = "https://files.pythonhosted.org/packages/52/4e/a7feb5a56b266304bc59f872ea07b728e14d5a64f1ad3a2cc01a3259c965/coverage-7.6.12-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2458f275944db8129f95d91aee32c828a408481ecde3b30af31d552c2ce284a0", size = 253988 },
|
||||
{ url = "https://files.pythonhosted.org/packages/65/19/069fec4d6908d0dae98126aa7ad08ce5130a6decc8509da7740d36e8e8d2/coverage-7.6.12-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a9d8be07fb0832636a0f72b80d2a652fe665e80e720301fb22b191c3434d924", size = 249697 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1c/da/5b19f09ba39df7c55f77820736bf17bbe2416bbf5216a3100ac019e15839/coverage-7.6.12-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14d47376a4f445e9743f6c83291e60adb1b127607a3618e3185bbc8091f0467b", size = 252033 },
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/89/4c2750df7f80a7872267f7c5fe497c69d45f688f7b3afe1297e52e33f791/coverage-7.6.12-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:b95574d06aa9d2bd6e5cc35a5bbe35696342c96760b69dc4287dbd5abd4ad51d", size = 251535 },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/3b/6d3ae3c1cc05f1b0460c51e6f6dcf567598cbd7c6121e5ad06643974703c/coverage-7.6.12-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:ecea0c38c9079570163d663c0433a9af4094a60aafdca491c6a3d248c7432827", size = 249192 },
|
||||
{ url = "https://files.pythonhosted.org/packages/6e/8e/c14a79f535ce41af7d436bbad0d3d90c43d9e38ec409b4770c894031422e/coverage-7.6.12-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:2251fabcfee0a55a8578a9d29cecfee5f2de02f11530e7d5c5a05859aa85aee9", size = 250627 },
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/79/b7cee656cfb17a7f2c1b9c3cee03dd5d8000ca299ad4038ba64b61a9b044/coverage-7.6.12-cp313-cp313t-win32.whl", hash = "sha256:eb5507795caabd9b2ae3f1adc95f67b1104971c22c624bb354232d65c4fc90b3", size = 212033 },
|
||||
{ url = "https://files.pythonhosted.org/packages/b6/c3/f7aaa3813f1fa9a4228175a7bd368199659d392897e184435a3b66408dd3/coverage-7.6.12-cp313-cp313t-win_amd64.whl", hash = "sha256:f60a297c3987c6c02ffb29effc70eadcbb412fe76947d394a1091a3615948e2f", size = 213240 },
|
||||
{ url = "https://files.pythonhosted.org/packages/fb/b2/f655700e1024dec98b10ebaafd0cedbc25e40e4abe62a3c8e2ceef4f8f0a/coverage-7.6.12-py3-none-any.whl", hash = "sha256:eb8668cfbc279a536c633137deeb9435d2962caec279c3f8cf8b91fff6ff8953", size = 200552 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d7/4b/cbd8e699e64a6f16ca3a8220661b5f83792b3017d0f79807cb8708d33913/iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3", size = 4646 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ef/a6/62565a6e1cf69e10f5727360368e451d4b7f58beeac6173dc9db836a5b46/iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374", size = 5892 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "loguru"
|
||||
version = "0.7.3"
|
||||
@ -36,6 +84,52 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/29/0348de65b8cc732daa3e33e67806420b2ae89bdce2b04af740289c5c6c8c/loguru-0.7.3-py3-none-any.whl", hash = "sha256:31a33c10c8e1e10422bfd431aeb5d351c7cf7fa671e3c4df004162264b28220c", size = 61595 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "24.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/63/68dbb6eb2de9cb10ee4c9c14a0148804425e13c4fb20d61cce69f53106da/packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f", size = 163950 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/ef/eb23f262cca3c0c4eb7ab1933c3b1f03d021f2c48f54763065b6f0e321be/packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759", size = 65451 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.5.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/96/2d/02d4312c973c6050a18b314a5ad0b3210edb65a906f868e31c111dede4a6/pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1", size = 67955 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/5f/e351af9a41f866ac3f1fac4ca0613908d9a41741cfcf2228f4ad853b697d/pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669", size = 20556 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.3.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/30/3d/64ad57c803f1fa1e963a7946b6e0fea4a70df53c1a7fed304586539c2bac/pytest-8.3.5-py3-none-any.whl", hash = "sha256:c69214aa47deac29fad6c2a4f590b9c4a9fdb16a403176fe154b79c0b4d4d820", size = 343634 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-cov"
|
||||
version = "6.0.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "coverage" },
|
||||
{ name = "pytest" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/be/45/9b538de8cef30e17c7b45ef42f538a94889ed6a16f2387a6c89e73220651/pytest-cov-6.0.0.tar.gz", hash = "sha256:fde0b595ca248bb8e2d76f020b465f3b107c9632e6a1d1705f17834c89dcadc0", size = 66945 }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/36/3b/48e79f2cd6a61dbbd4807b4ed46cb564b4fd50a76166b1c4ea5c1d9e2371/pytest_cov-6.0.0-py3-none-any.whl", hash = "sha256:eee6f1b9e61008bd34975a4d5bab25801eb31898b032dd55addc93e96fcaaa35", size = 22949 },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "win32-setctime"
|
||||
version = "1.2.0"
|
||||
@ -54,8 +148,17 @@ dependencies = [
|
||||
{ name = "loguru" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-cov" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "click", specifier = ">=8.1.8" },
|
||||
{ name = "loguru", specifier = ">=0.7.3" },
|
||||
{ name = "pytest", marker = "extra == 'dev'", specifier = ">=8.3.5" },
|
||||
{ name = "pytest-cov", marker = "extra == 'dev'", specifier = ">=6.0.0" },
|
||||
]
|
||||
provides-extras = ["dev"]
|
||||
|
||||
5
zig_fetch_py/__init__.py
Normal file
5
zig_fetch_py/__init__.py
Normal file
@ -0,0 +1,5 @@
|
||||
"""
|
||||
zig-fetch-py - A tool to parse Zig Object Notation (ZON) files and convert them to JSON.
|
||||
"""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
60
zig_fetch_py/main.py
Normal file
60
zig_fetch_py/main.py
Normal file
@ -0,0 +1,60 @@
|
||||
"""
|
||||
Command-line interface for the ZON parser.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import click
|
||||
from loguru import logger
|
||||
|
||||
from zig_fetch_py.parser import parse_zon_file
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("file", type=click.Path(exists=True, readable=True))
|
||||
@click.option(
|
||||
"-o",
|
||||
"--output",
|
||||
type=click.Path(writable=True),
|
||||
help="Output JSON file path (default: stdout)",
|
||||
)
|
||||
@click.option("-p", "--pretty", is_flag=True, help="Pretty print JSON output")
|
||||
@click.option("-v", "--verbose", is_flag=True, help="Enable verbose logging")
|
||||
def main(file, output, pretty, verbose):
|
||||
"""Parse ZON files and convert to JSON.
|
||||
|
||||
This tool parses Zig Object Notation (ZON) files and converts them to JSON format.
|
||||
"""
|
||||
# Configure logging
|
||||
log_level = "DEBUG" if verbose else "INFO"
|
||||
logger.remove() # Remove default handler
|
||||
logger.add(sys.stderr, level=log_level)
|
||||
|
||||
logger.info(f"Processing file: {file}")
|
||||
|
||||
try:
|
||||
result = parse_zon_file(file)
|
||||
|
||||
indent = 4 if pretty else None
|
||||
json_str = json.dumps(result, indent=indent)
|
||||
|
||||
if output:
|
||||
logger.info(f"Writing output to: {output}")
|
||||
with open(output, "w") as f:
|
||||
f.write(json_str)
|
||||
else:
|
||||
logger.debug("Writing output to stdout")
|
||||
click.echo(json_str)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
# This is only executed when the module is run directly
|
||||
if __name__ == "__main__":
|
||||
# When imported as a module, click will handle the function call
|
||||
# When run directly, we need to call it explicitly
|
||||
main()
|
||||
@ -1,11 +1,11 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Union, Tuple
|
||||
"""
|
||||
ZON parser module - Parses Zig Object Notation (ZON) files.
|
||||
"""
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any, Dict, List, Union, Tuple, Optional
|
||||
|
||||
import click
|
||||
from loguru import logger
|
||||
|
||||
|
||||
@ -14,12 +14,13 @@ class ZonParser:
|
||||
A parser for Zig Object Notation (ZON) files.
|
||||
"""
|
||||
|
||||
content: str
|
||||
pos: int
|
||||
line: int
|
||||
col: int
|
||||
|
||||
def __init__(self, content: str):
|
||||
"""
|
||||
Initialize the parser with ZON content.
|
||||
|
||||
Args:
|
||||
content: The ZON content to parse
|
||||
"""
|
||||
self.content = content
|
||||
self.pos = 0
|
||||
self.line = 1
|
||||
@ -314,7 +315,15 @@ class ZonParser:
|
||||
|
||||
|
||||
def parse_zon_file(file_path: str) -> Dict[str, Any]:
|
||||
"""Parse a ZON file and return a Python dictionary."""
|
||||
"""
|
||||
Parse a ZON file and return a Python dictionary.
|
||||
|
||||
Args:
|
||||
file_path: Path to the ZON file
|
||||
|
||||
Returns:
|
||||
Dictionary representation of the ZON file
|
||||
"""
|
||||
logger.debug(f"Parsing ZON file: {file_path}")
|
||||
with open(file_path, "r") as f:
|
||||
content = f.read()
|
||||
@ -325,46 +334,17 @@ def parse_zon_file(file_path: str) -> Dict[str, Any]:
|
||||
return result
|
||||
|
||||
|
||||
@click.command()
|
||||
@click.argument("file", type=click.Path(exists=True, readable=True))
|
||||
@click.option(
|
||||
"-o",
|
||||
"--output",
|
||||
type=click.Path(writable=True),
|
||||
help="Output JSON file path (default: stdout)",
|
||||
)
|
||||
@click.option("-p", "--pretty", is_flag=True, help="Pretty print JSON output")
|
||||
@click.option("-v", "--verbose", is_flag=True, help="Enable verbose logging")
|
||||
def main(file, output, pretty, verbose):
|
||||
"""Parse ZON files and convert to JSON.
|
||||
|
||||
This tool parses Zig Object Notation (ZON) files and converts them to JSON format.
|
||||
def zon_to_json(zon_content: str, indent: Optional[int] = None) -> str:
|
||||
"""
|
||||
# Configure logging
|
||||
log_level = "DEBUG" if verbose else "INFO"
|
||||
logger.remove() # Remove default handler
|
||||
logger.add(sys.stderr, level=log_level)
|
||||
Convert ZON content to JSON string.
|
||||
|
||||
logger.info(f"Processing file: {file}")
|
||||
Args:
|
||||
zon_content: ZON content as string
|
||||
indent: Number of spaces for indentation (None for compact JSON)
|
||||
|
||||
try:
|
||||
result = parse_zon_file(file)
|
||||
|
||||
indent = 4 if pretty else None
|
||||
json_str = json.dumps(result, indent=indent)
|
||||
|
||||
if output:
|
||||
logger.info(f"Writing output to: {output}")
|
||||
with open(output, "w") as f:
|
||||
f.write(json_str)
|
||||
else:
|
||||
logger.debug("Writing output to stdout")
|
||||
click.echo(json_str)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main() # pylint: disable=no-value-for-parameter
|
||||
Returns:
|
||||
JSON string
|
||||
"""
|
||||
parser = ZonParser(zon_content)
|
||||
result = parser.parse()
|
||||
return json.dumps(result, indent=indent)
|
||||
Reference in New Issue
Block a user