Skip to content

Commit

Permalink
feat: rework
Browse files Browse the repository at this point in the history
  • Loading branch information
BlueGlassBlock committed Nov 16, 2024
1 parent 3992e37 commit 027786f
Show file tree
Hide file tree
Showing 25 changed files with 1,212 additions and 1,547 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,4 @@ cython_debug/

# Temporary files, used in testing.
temp/
.pdm-python
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
repos:
- repo: https://github.com/psf/black
rev: 22.10.0
rev: 24.10.0
hooks:
- id: black
# It is recommended to specify the latest version of Python
# supported by your project here, or alternatively use
# pre-commit's default_language_version, see
# https://pre-commit.com/#top_level-default_language_version
language_version: python3.9
language_version: python3.11

- repo: https://github.com/pycqa/isort
rev: 5.10.1
rev: 5.13.2
hooks:
- id: isort
name: isort (python)

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.3.0
rev: v5.0.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace
Expand Down
8 changes: 3 additions & 5 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,10 @@
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "python",
"name": "Python 调试程序: 模块",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal",
"justMyCode": false
"module": "pytest"
}
]
}
37 changes: 2 additions & 35 deletions docs/index.md
Original file line number Diff line number Diff line change
@@ -1,41 +1,8 @@
# Kayaku

::: kayaku.initialize

::: kayaku.config

!!! note
Please note that `config` is routed to real config implementation at runtime.

::: kayaku.model.config_stub
options:
show_root_heading: false
show_root_toc_entry: false
show_source: false

::: kayaku.model.config_impl
options:
show_root_heading: false
show_root_toc_entry: false

::: kayaku.default

::: kayaku.utils.copying_field_stub
options:
show_root_heading: false
show_root_toc_entry: false
show_source: false


::: kayaku.bootstrap

::: kayaku.save_all

::: kayaku.create

::: kayaku.save
::: kayaku.Kayaku

::: kayaku.pretty.Prettifier
options:
merge_init_into_class: true
members: false
members: false
7 changes: 1 addition & 6 deletions kayaku/__init__.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,4 @@
from .domain import bootstrap as bootstrap
from .domain import initialize as initialize
from .domain import save_all as save_all
from .model import config as config
from .model import create as create
from .model import save as save
from .manager import Kayaku
from .utils import copying_field

default = copying_field
104 changes: 61 additions & 43 deletions kayaku/backend/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import re
from datetime import date, datetime, time
from enum import Enum
from typing import Any, Generic, List, Tuple, TypeVar, overload
from typing import TYPE_CHECKING, Any, Generic, List, Tuple, TypeVar, overload

from typing_extensions import Self, TypeAlias

Expand Down Expand Up @@ -117,7 +117,6 @@ def __repr__(self) -> str:
class Quote(Enum):
"""Known quotes formats"""

value: str
SINGLE = "'"
DOUBLE = '"'

Expand Down Expand Up @@ -162,23 +161,45 @@ def __post_init__(self, origin: str | None = None) -> Self:
self.origin = origin
return super().__post_init__()

def __round_dump__(self) -> str:
...
def __round_dump__(self) -> str: ...


class Integer(JNumber, int):
class Float(float, JNumber):
"""
A JSON integer compatible with Python's `int`.
A JSON float compatible with Python's `float`.
"""

def __str__(self) -> str:
return int.__repr__(self)

def __round_dump__(self) -> str:
if self.origin and int(self.origin) == self:
return self.origin
if self.origin:
constructed = float(self.origin)
if (math.isnan(constructed) and math.isnan(self)) or self == constructed:
return self.origin

return float.__repr__(self).replace("nan", "NaN").replace("inf", "Infinity")

return int.__repr__(self)

if TYPE_CHECKING:

class Integer(int, Float):
"""
A JSON integer compatible with Python's `int`.
"""

else:

class Integer(int, JNumber):
"""
A JSON integer compatible with Python's `int`.
"""

def __str__(self) -> str:
return int.__repr__(self)

def __round_dump__(self) -> str:
if self.origin and int(self.origin) == self:
return self.origin

return int.__repr__(self)


class HexInteger(Integer):
Expand All @@ -196,20 +217,6 @@ def __round_dump__(self) -> str:
return hex(self)


class Float(JNumber, float):
"""
A JSON float compatible with Python's `float`.
"""

def __round_dump__(self) -> str:
if self.origin:
constructed = float(self.origin)
if (math.isnan(constructed) and math.isnan(self)) or self == constructed:
return self.origin

return float.__repr__(self).replace("nan", "NaN").replace("inf", "Infinity")


AnyNumber: TypeAlias = "Integer | Float"

T = TypeVar("T")
Expand All @@ -235,7 +242,22 @@ def __hash__(self) -> int:
return self.value.__hash__()


Value: TypeAlias = "JObject | Array | JString | JNumber | JWrapper | bool | None"
class BoolWrapper(Integer, JWrapper[bool]):
"""
A JSON boolean compatible with Python's `bool`.
"""

def __init__(self, value):
super().__init__(value)

def __str__(self) -> str:
return str(self.value)

def __round_dump__(self) -> str:
return str(self.value).lower()


Value: TypeAlias = "JObject | Array | JString | JNumber | JWrapper | None"
"""
A type alias matching the JSON Value.
"""
Expand All @@ -250,43 +272,39 @@ def __hash__(self) -> int:


@overload
def convert(obj: dict) -> JObject:
...
def convert(obj: dict) -> JObject: ...


@overload
def convert(obj: list | tuple) -> Array: ...


@overload
def convert(obj: "list | tuple") -> Array:
...
def convert(obj: str) -> JString: ...


@overload
def convert(obj: str) -> JString:
...
def convert(obj: bool) -> BoolWrapper: ...


@overload
def convert(obj: int) -> Integer:
...
def convert(obj: int) -> Integer: ...


@overload
def convert(obj: float) -> Float:
...
def convert(obj: float) -> Float: ...


@overload
def convert(obj: "bool") -> JWrapper[bool]:
...
def convert(obj: None) -> JWrapper[None]: ...


@overload
def convert(obj: None) -> JWrapper[None]:
...
def convert(obj: JSONType_T) -> JSONType_T: ...


@overload
def convert(obj: JSONType_T) -> JSONType_T:
...
def convert(obj: Any) -> JType: ...


def convert(obj: Any) -> JType:
Expand Down
67 changes: 67 additions & 0 deletions kayaku/bi_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from __future__ import annotations

from collections.abc import Iterable, Sequence

from .spec import DestWithMount, PathSpec, SourceSpec


class Suffix:
bound: tuple[SourceSpec, PathSpec] | None

def __init__(self) -> None:
self.bound = None
self.nxt: dict[str, Suffix] = {}

def insert(self, frags: Iterable[str]) -> Suffix:
node = self
for frag in frags:
node = node.nxt.setdefault(frag, Suffix())
return node

def lookup(
self, frags: Iterable[str]
) -> tuple[int, tuple[SourceSpec, PathSpec] | None]:
node = self
bound = self.bound
last_index = 0
for index, frag in enumerate(frags):
if nxt_nd := node.nxt.get(frag, None):
node = nxt_nd
if node.bound:
bound = node.bound
last_index = index
return last_index, bound


class Prefix:
suffix: Suffix | None

def __init__(self) -> None:
self.suffix = None
self.nxt: dict[str, Prefix] = {}

def insert(self, frags: Iterable[str]) -> Suffix:
node = self
for frag in frags:
node = node.nxt.setdefault(frag, Prefix())
if not node.suffix:
node.suffix = Suffix()
return node.suffix

def lookup(
self, frags: Sequence[str], index: int = 0
) -> tuple[tuple[SourceSpec, PathSpec], DestWithMount] | None:
if index < len(frags) and (nxt_nd := self.nxt.get(frags[index], None)):
if lookup_res := nxt_nd.lookup(frags, index + 1):
return lookup_res
if self.suffix:
suffix_ind, spec = self.suffix.lookup(reversed(frags[index:]))
if spec:
src_spec, path_spec = spec
parts = (
src_spec.section.prefix
+ list(frags[index : -suffix_ind or None])
+ src_spec.section.suffix
)
if formatted := path_spec.format(parts):
return spec, formatted
Loading

0 comments on commit 027786f

Please sign in to comment.