Skip to content

Commit 0e47673

Browse files
committed
fix for lists
1 parent eb75ab9 commit 0e47673

File tree

3 files changed

+21
-13
lines changed

3 files changed

+21
-13
lines changed

accessor/__init__.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"""
55

66
from functools import wraps
7-
from typing import Any, Callable, Dict, List, Optional, Union
7+
from typing import Any, Callable, Union
88

99
import operator
1010

@@ -41,6 +41,13 @@ def _str_slice(s):
4141
return ":".join(["" if x is None else str(x) for x in t])
4242

4343

44+
def get(v, k):
45+
try:
46+
return v[k]
47+
except (KeyError, TypeError, IndexError, AttributeError):
48+
return None
49+
50+
4451
class Accessor(metaclass=Meta):
4552
"""Return a callable object that fetches the given item(s) from its operand.
4653
@@ -64,13 +71,10 @@ def __getattr__(self, name: str) -> "Accessor":
6471
def __getitem__(self, name: Union[str, int, slice]) -> "Accessor":
6572
def accessor(x: Any) -> Any:
6673
value = x if self._accessor is None else self._accessor(x) # self(x)
67-
try:
68-
if not isinstance(name, (int, slice)) and isinstance(value, list):
69-
return [v[name] for v in value]
70-
else:
71-
return value[name]
72-
except (KeyError, TypeError, IndexError, AttributeError):
73-
return None
74+
if not isinstance(name, (int, slice)) and isinstance(value, list):
75+
return [get(v, name) for v in value]
76+
else:
77+
return get(value, name)
7478

7579
# Pre-compute name and path strings
7680
if isinstance(name, slice):
@@ -99,14 +103,14 @@ def keys(*getters: "Accessor") -> Callable[[Any], tuple]:
99103
return lambda x: tuple(n._path for n in getters)
100104

101105

102-
def items(*getters: "Accessor", prefix: str = "") -> Callable[[Any], Dict[str, Any]]:
106+
def items(*getters: "Accessor", prefix: str = "") -> Callable[[Any], dict[str, Any]]:
103107
"""Return func extracting names and values of multiple getters as tuple."""
104108
if prefix:
105109
return lambda x: {prefix + n._name: n(x) for n in getters}
106110
return lambda x: {n._name: n(x) for n in getters}
107111

108112

109-
def select(*getters: "Accessor", **name_getters: "Accessor") -> Callable[[Any], Dict[str, Any]]:
113+
def select(*getters: "Accessor", **name_getters: "Accessor") -> Callable[[Any], dict[str, Any]]:
110114
"""Return func extracting values of multiple getters as dict.
111115
112116
getters: list of getters for dict entries with _name key

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
[project]
22
name = "python-accessor"
3-
version = "1.0.0"
3+
version = "1.0.2"
44
description = "Access nested dicts"
55
readme = "README.md"
6-
requires-python = ">=3.9"
6+
requires-python = ">=3.10"
77
license = "MIT AND (Apache-2.0 OR BSD-2-Clause)"
88
authors = [{ name = "Jakub Jagielka", email = "jjagielka@gmail.com" }]
99
keywords = ["accessor", "api", "itemgetter", "rest"]

tests/test_edge_cases.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def test_non_dict_input(self):
2929
self.assertIsNone(_.a.b.c(123))
3030
self.assertIsNone(_.a.b.c(True))
3131
# Lists are handled specially - they return a list of None values
32-
self.assertIsNone(_.a.b.c([1, 2, 3]))
32+
self.assertEqual(_.a.b.c([1, 2, 3]), [None, None, None])
3333

3434
def test_missing_keys(self):
3535
"""Test handling of missing keys."""
@@ -165,6 +165,10 @@ def test_special_characters_in_keys(self):
165165
self.assertIsNone(_.key_with_dash(data)) # This won't work due to hyphen
166166
# The others would need bracket notation which isn't implemented
167167

168+
self.assertEqual(_["key-with-dash"](data), 1) # This will work though
169+
self.assertEqual(_["key.with.dots"](data), 3)
170+
self.assertEqual(_["key with spaces"](data), 4)
171+
168172
def test_very_large_structures(self):
169173
"""Test with very large data structures."""
170174
# Create a large list

0 commit comments

Comments
 (0)