init
This commit is contained in:
10
.gitignore
vendored
Normal file
10
.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Python-generated files
|
||||||
|
__pycache__/
|
||||||
|
*.py[oc]
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
wheels/
|
||||||
|
*.egg-info
|
||||||
|
|
||||||
|
# Virtual environments
|
||||||
|
.venv
|
||||||
1
.python-version
Normal file
1
.python-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
3.12
|
||||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"python.analysis.typeCheckingMode": "basic"
|
||||||
|
}
|
||||||
39
README.md
Normal file
39
README.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
```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
|
||||||
|
// ```
|
||||||
|
.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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.paths = .{""},
|
||||||
|
.fingerprint = 0xa66330b97eb969ae, // Changing this has security and trust implications.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It's called `zon`, the Zig Object Notation. I think You need to parse it first (convert to json) and then parse the json.
|
||||||
370
main.py
Normal file
370
main.py
Normal file
@ -0,0 +1,370 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any, Dict, List, Union, Tuple
|
||||||
|
|
||||||
|
import click
|
||||||
|
from loguru import logger
|
||||||
|
|
||||||
|
|
||||||
|
class ZonParser:
|
||||||
|
"""
|
||||||
|
A parser for Zig Object Notation (ZON) files.
|
||||||
|
"""
|
||||||
|
|
||||||
|
content: str
|
||||||
|
pos: int
|
||||||
|
line: int
|
||||||
|
col: int
|
||||||
|
|
||||||
|
def __init__(self, content: str):
|
||||||
|
self.content = content
|
||||||
|
self.pos = 0
|
||||||
|
self.line = 1
|
||||||
|
self.col = 1
|
||||||
|
|
||||||
|
def parse(self) -> Dict[str, Any]:
|
||||||
|
"""Parse ZON content and return a Python dictionary."""
|
||||||
|
result = self._parse_value()
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _current_char(self) -> str:
|
||||||
|
if self.pos >= len(self.content):
|
||||||
|
return ""
|
||||||
|
return self.content[self.pos]
|
||||||
|
|
||||||
|
def _next_char(self) -> str:
|
||||||
|
self.pos += 1
|
||||||
|
if self.pos - 1 < len(self.content):
|
||||||
|
char = self.content[self.pos - 1]
|
||||||
|
if char == "\n":
|
||||||
|
self.line += 1
|
||||||
|
self.col = 1
|
||||||
|
else:
|
||||||
|
self.col += 1
|
||||||
|
return char
|
||||||
|
return ""
|
||||||
|
|
||||||
|
def _skip_whitespace_and_comments(self):
|
||||||
|
while self.pos < len(self.content):
|
||||||
|
char = self._current_char()
|
||||||
|
|
||||||
|
# Skip whitespace
|
||||||
|
if char.isspace():
|
||||||
|
self._next_char()
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip comments
|
||||||
|
if (
|
||||||
|
char == "/"
|
||||||
|
and self.pos + 1 < len(self.content)
|
||||||
|
and self.content[self.pos + 1] == "/"
|
||||||
|
):
|
||||||
|
# Skip to end of line
|
||||||
|
while self.pos < len(self.content) and self._current_char() != "\n":
|
||||||
|
self._next_char()
|
||||||
|
continue
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
def _parse_value(self) -> Any:
|
||||||
|
self._skip_whitespace_and_comments()
|
||||||
|
|
||||||
|
char = self._current_char()
|
||||||
|
|
||||||
|
if char == ".":
|
||||||
|
self._next_char() # Skip the dot
|
||||||
|
|
||||||
|
# Check if it's an object
|
||||||
|
if self._current_char() == "{":
|
||||||
|
return self._parse_object()
|
||||||
|
|
||||||
|
# Check if it's an array
|
||||||
|
if self._current_char() == "[":
|
||||||
|
return self._parse_array()
|
||||||
|
|
||||||
|
# It's a field name or a special value
|
||||||
|
return self._parse_identifier()
|
||||||
|
|
||||||
|
elif char == '"':
|
||||||
|
return self._parse_string()
|
||||||
|
elif char.isdigit() or char == "-":
|
||||||
|
return self._parse_number()
|
||||||
|
elif char == "t" or char == "f":
|
||||||
|
return self._parse_boolean()
|
||||||
|
elif char == "n" and self.content[self.pos : self.pos + 4] == "null":
|
||||||
|
self.pos += 4
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Unexpected character '{char}' at line {self.line}, column {self.col}"
|
||||||
|
)
|
||||||
|
|
||||||
|
def _parse_object(self) -> Dict[str, Any]:
|
||||||
|
result = {}
|
||||||
|
|
||||||
|
# Skip the opening brace
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self._skip_whitespace_and_comments()
|
||||||
|
|
||||||
|
# Check for closing brace
|
||||||
|
if self._current_char() == "}":
|
||||||
|
self._next_char()
|
||||||
|
break
|
||||||
|
|
||||||
|
# Parse key
|
||||||
|
if self._current_char() == ".":
|
||||||
|
self._next_char() # Skip the dot
|
||||||
|
key = self._parse_identifier()
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Expected '.' before key at line {self.line}, column {self.col}"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._skip_whitespace_and_comments()
|
||||||
|
|
||||||
|
# Parse equals sign or check if it's a shorthand notation
|
||||||
|
if self._current_char() == "=":
|
||||||
|
self._next_char()
|
||||||
|
self._skip_whitespace_and_comments()
|
||||||
|
value = self._parse_value()
|
||||||
|
else:
|
||||||
|
# Shorthand notation where key is the same as value
|
||||||
|
value = key
|
||||||
|
|
||||||
|
result[key] = value
|
||||||
|
|
||||||
|
self._skip_whitespace_and_comments()
|
||||||
|
|
||||||
|
# Check for comma
|
||||||
|
if self._current_char() == ",":
|
||||||
|
self._next_char()
|
||||||
|
elif self._current_char() != "}":
|
||||||
|
raise ValueError(
|
||||||
|
f"Expected ',' or '}}' at line {self.line}, column {self.col}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _parse_array(self) -> List[Any]:
|
||||||
|
result = []
|
||||||
|
|
||||||
|
# Skip the opening bracket
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
self._skip_whitespace_and_comments()
|
||||||
|
|
||||||
|
# Check for closing bracket
|
||||||
|
if self._current_char() == "]":
|
||||||
|
self._next_char()
|
||||||
|
break
|
||||||
|
|
||||||
|
# Parse value
|
||||||
|
value = self._parse_value()
|
||||||
|
result.append(value)
|
||||||
|
|
||||||
|
self._skip_whitespace_and_comments()
|
||||||
|
|
||||||
|
# Check for comma
|
||||||
|
if self._current_char() == ",":
|
||||||
|
self._next_char()
|
||||||
|
elif self._current_char() != "]":
|
||||||
|
raise ValueError(
|
||||||
|
f"Expected ',' or ']' at line {self.line}, column {self.col}"
|
||||||
|
)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _parse_identifier(self) -> str:
|
||||||
|
start = self.pos
|
||||||
|
|
||||||
|
# Handle quoted identifiers (like .@"lsp-codegen")
|
||||||
|
if (
|
||||||
|
self._current_char() == "@"
|
||||||
|
and self.pos + 1 < len(self.content)
|
||||||
|
and self.content[self.pos + 1] == '"'
|
||||||
|
):
|
||||||
|
self._next_char() # Skip @
|
||||||
|
return self._parse_string()
|
||||||
|
|
||||||
|
# Regular identifier
|
||||||
|
while self.pos < len(self.content):
|
||||||
|
char = self._current_char()
|
||||||
|
if char.isalnum() or char == "_" or char == "-":
|
||||||
|
self._next_char()
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
if start == self.pos:
|
||||||
|
raise ValueError(f"Empty identifier at line {self.line}, column {self.col}")
|
||||||
|
|
||||||
|
return self.content[start : self.pos]
|
||||||
|
|
||||||
|
def _parse_string(self) -> str:
|
||||||
|
result = ""
|
||||||
|
|
||||||
|
# Skip the opening quote
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
while self.pos < len(self.content) and self._current_char() != '"':
|
||||||
|
if self._current_char() == "\\":
|
||||||
|
self._next_char()
|
||||||
|
if self._current_char() == "n":
|
||||||
|
result += "\n"
|
||||||
|
elif self._current_char() == "t":
|
||||||
|
result += "\t"
|
||||||
|
elif self._current_char() == "r":
|
||||||
|
result += "\r"
|
||||||
|
elif self._current_char() == '"':
|
||||||
|
result += '"'
|
||||||
|
elif self._current_char() == "\\":
|
||||||
|
result += "\\"
|
||||||
|
else:
|
||||||
|
result += "\\" + self._current_char()
|
||||||
|
else:
|
||||||
|
result += self._current_char()
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
if self._current_char() != '"':
|
||||||
|
raise ValueError(
|
||||||
|
f"Unterminated string at line {self.line}, column {self.col}"
|
||||||
|
)
|
||||||
|
|
||||||
|
self._next_char() # Skip the closing quote
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _parse_number(self) -> Union[int, float]:
|
||||||
|
start = self.pos
|
||||||
|
|
||||||
|
# Handle hex numbers
|
||||||
|
if (
|
||||||
|
self._current_char() == "0"
|
||||||
|
and self.pos + 1 < len(self.content)
|
||||||
|
and self.content[self.pos + 1].lower() == "x"
|
||||||
|
):
|
||||||
|
self._next_char() # Skip 0
|
||||||
|
self._next_char() # Skip x
|
||||||
|
|
||||||
|
hex_start = self.pos
|
||||||
|
while self.pos < len(self.content) and (
|
||||||
|
self._current_char().isdigit()
|
||||||
|
or self._current_char().lower() in "abcdef"
|
||||||
|
):
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
hex_str = self.content[hex_start : self.pos]
|
||||||
|
return int(hex_str, 16)
|
||||||
|
|
||||||
|
# Regular number
|
||||||
|
is_float = False
|
||||||
|
|
||||||
|
# Handle sign
|
||||||
|
if self._current_char() == "-":
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
# Handle digits before decimal point
|
||||||
|
while self.pos < len(self.content) and self._current_char().isdigit():
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
# Handle decimal point
|
||||||
|
if self._current_char() == ".":
|
||||||
|
is_float = True
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
# Handle digits after decimal point
|
||||||
|
while self.pos < len(self.content) and self._current_char().isdigit():
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
# Handle exponent
|
||||||
|
if self._current_char().lower() == "e":
|
||||||
|
is_float = True
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
# Handle exponent sign
|
||||||
|
if self._current_char() in "+-":
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
# Handle exponent digits
|
||||||
|
while self.pos < len(self.content) and self._current_char().isdigit():
|
||||||
|
self._next_char()
|
||||||
|
|
||||||
|
num_str = self.content[start : self.pos]
|
||||||
|
|
||||||
|
if is_float:
|
||||||
|
return float(num_str)
|
||||||
|
else:
|
||||||
|
return int(num_str)
|
||||||
|
|
||||||
|
def _parse_boolean(self) -> bool:
|
||||||
|
if self.content[self.pos : self.pos + 4] == "true":
|
||||||
|
self.pos += 4
|
||||||
|
return True
|
||||||
|
elif self.content[self.pos : self.pos + 5] == "false":
|
||||||
|
self.pos += 5
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
raise ValueError(
|
||||||
|
f"Expected 'true' or 'false' at line {self.line}, column {self.col}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_zon_file(file_path: str) -> Dict[str, Any]:
|
||||||
|
"""Parse a ZON file and return a Python dictionary."""
|
||||||
|
logger.debug(f"Parsing ZON file: {file_path}")
|
||||||
|
with open(file_path, "r") as f:
|
||||||
|
content = f.read()
|
||||||
|
|
||||||
|
parser = ZonParser(content)
|
||||||
|
result = parser.parse()
|
||||||
|
logger.debug(f"Successfully parsed ZON file")
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main() # pylint: disable=no-value-for-parameter
|
||||||
23
pyproject.toml
Normal file
23
pyproject.toml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
[project]
|
||||||
|
name = "zig-fetch-py"
|
||||||
|
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",
|
||||||
|
]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
zon2json = "zig_fetch_py.main:main"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["hatchling"]
|
||||||
|
build-backend = "hatchling.build"
|
||||||
|
|
||||||
|
[tool.hatch.build.targets.wheel]
|
||||||
|
packages = ["zig_fetch_py"]
|
||||||
|
|
||||||
|
[tool.ruff]
|
||||||
|
line-length = 100
|
||||||
29
test.zon
Normal file
29
test.zon
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
.{
|
||||||
|
.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",
|
||||||
|
.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,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
.paths = .{""},
|
||||||
|
.fingerprint = 0xa66330b97eb969ae, // Changing this has security and trust implications.
|
||||||
|
}
|
||||||
61
uv.lock
generated
Normal file
61
uv.lock
generated
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
version = 1
|
||||||
|
revision = 1
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "click"
|
||||||
|
version = "8.1.8"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "colorama"
|
||||||
|
version = "0.4.6"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697 }
|
||||||
|
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 = "loguru"
|
||||||
|
version = "0.7.3"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||||
|
{ name = "win32-setctime", marker = "sys_platform == 'win32'" },
|
||||||
|
]
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559 }
|
||||||
|
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 = "win32-setctime"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/b3/8f/705086c9d734d3b663af0e9bb3d4de6578d08f46b1b101c2442fd9aecaa2/win32_setctime-1.2.0.tar.gz", hash = "sha256:ae1fdf948f5640aae05c511ade119313fb6a30d7eabe25fef9764dca5873c4c0", size = 4867 }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/07/c6fe3ad3e685340704d314d765b7912993bcb8dc198f0e7a89382d37974b/win32_setctime-1.2.0-py3-none-any.whl", hash = "sha256:95d644c4e708aba81dc3704a116d8cbc974d70b3bdb8be1d150e36be6e9d1390", size = 4083 },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zig-fetch-py"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = { editable = "." }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "click" },
|
||||||
|
{ name = "loguru" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [
|
||||||
|
{ name = "click", specifier = ">=8.1.8" },
|
||||||
|
{ name = "loguru", specifier = ">=0.7.3" },
|
||||||
|
]
|
||||||
Reference in New Issue
Block a user