Skip to content

Commit 842719d

Browse files
fixed bug with integer keys
1 parent 1598b1d commit 842719d

7 files changed

Lines changed: 31 additions & 27 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "pyya"
3-
version = "0.1.13"
3+
version = "0.1.14"
44
description = "Convert YAML/TOML configuration files to Python objects"
55
readme = "README.md"
66
requires-python = ">=3.8"

pyya.egg-info/PKG-INFO

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Metadata-Version: 2.1
22
Name: pyya
3-
Version: 0.1.13
3+
Version: 0.1.14
44
Summary: Convert YAML/TOML configuration files to Python objects
55
Author-email: shadowy-pycoder <shadowy-pycoder@example.com>
66
Project-URL: Homepage, https://github.com/shadowy-pycoder/pyya

pyya/__init__.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,9 @@ def _merge_configs(
8282
logger.debug(f'section `{".".join(sections)}` already exists in {config}, skipping')
8383
sections.pop()
8484

85-
def _sanitize_section(section: str) -> str:
85+
def _sanitize_section(section: Any) -> Any:
86+
if not isinstance(section, str):
87+
return section
8688
if convert_keys_to_snake_case:
8789
logger.debug(f'converting section `{section}` to snake case')
8890
section = _to_snake(section)
@@ -135,6 +137,7 @@ class ExtraBase(BaseModel):
135137
@model_validator(mode='before')
136138
@classmethod
137139
def validator(cls, values: Any) -> Any:
140+
values = {str(k): v for k, v in values.items()}
138141
if cls.model_config.get('extra') == 'allow':
139142
extra, valid = {}, {}
140143
for key, value in values.items():
@@ -155,6 +158,11 @@ def extra_flat(self) -> Any:
155158
extra_flat.update(data)
156159
return extra_flat
157160

161+
def is_identifier(data: Any) -> bool:
162+
if not isinstance(data, str):
163+
return False
164+
return not keyword.iskeyword(data) and data.isidentifier()
165+
158166
def _model_and_stub_from_dict(
159167
name: str, data: Dict[str, Any], path: Optional[List[str]] = None
160168
) -> Tuple[Type[ExtraBase], str]:
@@ -168,38 +176,35 @@ def _model_and_stub_from_dict(
168176
nested_stubs = []
169177
py_type: Any
170178
for section, entry in data.items():
179+
if not is_identifier(section):
180+
continue
171181
if isinstance(entry, Dict):
172182
nested_model, nested_stub = _model_and_stub_from_dict(section, entry, path + [name])
173-
if not keyword.iskeyword(section) and section.isidentifier():
174-
stub_lines.append(f' {section}: {class_name + section.capitalize()}')
175-
nested_stubs.append(nested_stub)
183+
stub_lines.append(f' {section}: {class_name + section.capitalize()}')
184+
nested_stubs.append(nested_stub)
176185
fields[section] = (nested_model, entry)
177186
elif isinstance(entry, list) and entry:
178187
first_item = entry[0]
179188
if isinstance(first_item, Dict):
180189
nested_model, nested_stub = _model_and_stub_from_dict(
181190
f'{section.capitalize()}_item', first_item, path + [name]
182191
)
183-
if not keyword.iskeyword(section) and section.isidentifier():
184-
stub_lines.append(f' {section}: list[{class_name + section.capitalize()}_item]')
185-
nested_stubs.append(nested_stub)
192+
stub_lines.append(f' {section}: list[{class_name + section.capitalize()}_item]')
193+
nested_stubs.append(nested_stub)
186194
fields[section] = (List[nested_model], entry) # type: ignore
187195
else:
188196
py_type = type(first_item)
189-
if not keyword.iskeyword(section) and section.isidentifier():
190-
stub_lines.append(f' {section}: list[{py_type.__name__}]')
197+
stub_lines.append(f' {section}: list[{py_type.__name__}]')
191198
fields[section] = (List[py_type], entry)
192199
elif isinstance(entry, list):
193-
if not keyword.iskeyword(section) and section.isidentifier():
194-
stub_lines.append(f' {section}: list[Any]')
200+
stub_lines.append(f' {section}: list[Any]')
195201
fields[section] = (List[Any], entry)
196202
else:
197203
py_type = type(entry)
198-
if not keyword.iskeyword(section) and section.isidentifier():
199-
stub_lines.append(f' {section}: {py_type.__name__}')
204+
stub_lines.append(f' {section}: {py_type.__name__}')
200205
fields[section] = (py_type, entry)
201206
if len(stub_lines) == 1:
202-
stub_lines[0] += ' ...'
207+
stub_lines = [f'class {class_name}(dict[Any, Any]): ...']
203208
stub_code = '\n\n'.join(nested_stubs + ['\n'.join(stub_lines)])
204209
return create_model(name, **fields, __base__=ExtraBase), stub_code
205210

tests/test_common.py

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,6 @@ def test_raise_err_default_corrupted() -> None:
5454
)
5555

5656

57-
def test_raise_err_sections_ignored_on_merge() -> None:
58-
with pytest.raises(pyya.PyyaError, match=r'Failed parsing `sections_ignored_on_merge`'):
59-
_ = pyya.init_config(
60-
config=config_path,
61-
default_config=default_config_path,
62-
sections_ignored_on_merge=[0], # type: ignore
63-
validate_data_types=False,
64-
replace_dashes_with_underscores=True,
65-
)
66-
67-
6857
def test_no_error_config_not_found() -> None:
6958
_ = pyya.init_config(config='missing.yaml', default_config=default_config_path)
7059

tests/test_yaml.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ def test_default_setup() -> None:
2020
assert len(config.cache.servers) == 1
2121
assert len(config.admins) == 1
2222
assert config.cache.ttlSeconds == 500
23+
assert config.errors[1] == 'error 1'
24+
assert config.environments['prod-env'][1] == 'test'
2325

2426

2527
def test_convert_snake_case() -> None:

tests/testdata/default.config.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,12 @@ environments:
5757
level: warn
5858
cache:
5959
ttl_seconds: 600
60+
1: "test"
6061

6162
flags: []
63+
64+
errors:
65+
1: "error 1"
66+
2: "error 2"
67+
3: "error 3"
68+
4: "error 4"

tests/testdata/extra.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ database:
1919

2020
extra:
2121
garbage: false
22+
1: true

0 commit comments

Comments
 (0)