-
-
Notifications
You must be signed in to change notification settings - Fork 5
Richer AccessorPath API #63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
1606a83
294f444
fd6398e
938fdab
ca0c2b2
6526cbc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -127,6 +127,17 @@ def __init__(self, accessor: NodeAccessor[N, K, V], *args: Any, separator: Optio | |
| object.__setattr__(self, 'accessor', accessor) | ||
| super().__init__(*args, separator=separator) | ||
|
|
||
| @classmethod | ||
| def _from_parts( | ||
| cls: Type[TAccessorPath], | ||
| args: Sequence[Any], | ||
| separator: Optional[str] = None, | ||
| accessor: Union[NodeAccessor[N, K, V], None] = None, | ||
| ) -> TAccessorPath: | ||
| if accessor is None: | ||
| raise ValueError("accessor must be provided") | ||
| return cls(accessor, *args, separator=separator) | ||
|
|
||
| @classmethod | ||
| def _from_parsed_parts( | ||
| cls: Type[TAccessorPath], | ||
|
|
@@ -159,87 +170,68 @@ def _make_child_relpath( | |
| parts, separator=self.separator, accessor=self.accessor, | ||
| ) | ||
|
|
||
| def __rtruediv__(self: TAccessorPath, key: Hashable) -> TAccessorPath: | ||
| try: | ||
| return self._from_parts( | ||
| (key, ) + self.parts, | ||
| separator=self.separator, | ||
| accessor=self.accessor, | ||
| ) | ||
| except TypeError: | ||
| return NotImplemented | ||
|
|
||
| def __floordiv__(self: TAccessorPath, key: K) -> TAccessorPath: | ||
p1c2u marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """Return a new existing path with the key appended.""" | ||
| if key not in self: | ||
| raise KeyError(key) | ||
| return self / key | ||
|
|
||
| def __rfloordiv__(self: TAccessorPath, key: K) -> TAccessorPath: | ||
p1c2u marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| """Return a new existing path with the key prepended.""" | ||
| new = key / self | ||
| if not new.exists(): | ||
| raise KeyError(key) | ||
| return new | ||
p1c2u marked this conversation as resolved.
Show resolved
Hide resolved
p1c2u marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| def __iter__(self: TAccessorPath) -> Iterator[TAccessorPath]: | ||
| """Iterate over all child paths.""" | ||
| for key in self.accessor.keys(self.parts): | ||
| yield self._make_child_relpath(key) | ||
|
|
||
| def __getitem__(self, key: K) -> Any: | ||
| if key not in self: | ||
| raise KeyError(key) | ||
| path = self / key | ||
| def __getitem__(self, key: K) -> V: | ||
| """Access a child path's value.""" | ||
| path = self // key | ||
| return path.read_value() | ||
|
|
||
| def __contains__(self, key: K) -> bool: | ||
| """Check if a key exists in the path.""" | ||
| return key in self.accessor.keys(self.parts) | ||
|
|
||
| def __len__(self) -> int: | ||
| """Return the number of child paths.""" | ||
| return self.accessor.len(self.parts) | ||
|
|
||
| def exists(self) -> bool: | ||
| """Check if the path exists.""" | ||
| return self.accessor.stat(self.parts) is not None | ||
p1c2u marked this conversation as resolved.
Show resolved
Hide resolved
p1c2u marked this conversation as resolved.
Show resolved
Hide resolved
Comment on lines
+214
to
+216
|
||
|
|
||
| def keys(self) -> Sequence[K]: | ||
| """Return all keys at the current path.""" | ||
| return self.accessor.keys(self.parts) | ||
|
|
||
| def getkey(self, key: K, default: Any = None) -> Any: | ||
| """Return the value for key if key is in the path, else default.""" | ||
| warnings.warn( | ||
| "'getkey' method is deprecated. Use 'key not in path' and 'path.read_value' instead.", | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| try: | ||
| return self[key] | ||
| except KeyError: | ||
| return default | ||
|
|
||
| def iter(self: TAccessorPath) -> Iterator[TAccessorPath]: | ||
| """Iterate over all child paths.""" | ||
| warnings.warn( | ||
| "'iter' method is deprecated. Use 'iter(path)' instead.", | ||
| DeprecationWarning, | ||
| ) | ||
| return iter(self) | ||
|
|
||
| def iteritems(self: TAccessorPath) -> Iterator[tuple[K, TAccessorPath]]: | ||
| """Return path's items.""" | ||
| warnings.warn( | ||
| "'iteritems' method is deprecated. Use 'items' instead.", | ||
| DeprecationWarning, | ||
| ) | ||
| return self.items() | ||
|
|
||
| def items(self: TAccessorPath) -> Iterator[tuple[K, TAccessorPath]]: | ||
| """Return path's items.""" | ||
| for key in self.accessor.keys(self.parts): | ||
| yield key, self._make_child_relpath(key) | ||
|
|
||
| def content(self) -> Any: | ||
| warnings.warn( | ||
| "'content' method is deprecated. Use 'read_value' instead.", | ||
| DeprecationWarning, | ||
| ) | ||
| return self.read_value() | ||
|
|
||
| def get(self, key: K, default: Any = None) -> Any: | ||
| """Return the child path for key if key is in the path, else default.""" | ||
| warnings.warn( | ||
| "'get' method is deprecated. Use 'key in path' and 'path / key' instead.", | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| if key in self: | ||
| return self / key | ||
| return default | ||
|
|
||
| @contextmanager | ||
| def open(self) -> Any: | ||
| """Open the path.""" | ||
| warnings.warn( | ||
| "'open' method is deprecated. Use 'read_value' instead.", | ||
| DeprecationWarning, | ||
| stacklevel=2, | ||
| ) | ||
| yield self.read_value() | ||
| """Return the value for key if key is in the path, else default.""" | ||
| try: | ||
| return self[key] | ||
| except KeyError: | ||
| return default | ||
|
Comment on lines
221
to
+232
|
||
|
|
||
| def read_value(self) -> Any: | ||
| def read_value(self) -> V: | ||
| """Return the path's value.""" | ||
| return self.accessor.read(self.parts) | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The return value for the 'type' key has changed from a string literal ('mapping' or 'list') to a type object (type(node)). This is a breaking API change that could affect consumers expecting string values. If this change is intentional, it should be clearly documented. Additionally, this will now include the type for all node values, not just Mappings and lists, which changes the semantics of when stat() returns a result versus None.