Skip to content

[bug] BoxKeyError: "dynaconf_merge_unique" with specific YAML files #1005

@sebastian-correa

Description

@sebastian-correa

Describe the bug
I'm getting BoxKeyError: "dynaconf_merge_unique" and AttributeError: 'int' object has no attribute 'lower' when I have a particularly nested YAML config file.

To Reproduce
Steps to reproduce the behavior:

  1. Having the following folder structure
Project structure
.
├── config.py
├── settings_test.local.yaml
└── settings_test.yaml

1 directory, 3 files
  1. Having the following config files:
Config files

settings_test.yaml

default:
  a_mapping:
    1: ["a string"]

and

settings_test.local.yaml

default:
  a_value: .inf
  1. Having the following app code:
Code

config.py

from pathlib import Path

from dynaconf import Dynaconf

settings = Dynaconf(
    settings_files=[Path(__file__).parent / "settings_test.yaml"],
    merge_enabled=True,
)

print(settings.as_dict())
  1. Executing under the following environment
Execution
$ python config.py

Expected behavior
The program should print a dict with the settings.

Environment (please complete the following information):

  • OS: MacOS 13.5.2 (22G91). Mac M1.
  • Dynaconf Version: 3.2.2
  • Frameworks in use: Nothing.

Additional context
Works in Dynaconf 3.2.1.

Full traceback:
Traceback (most recent call last):
  File "/Users/nix/Dev/dynaconf/dynaconf/utils/boxing.py", line 49, in __getitem__
    return super().__getitem__(item, *args, **kwargs)
  File "/Users/nix/Dev/dynaconf/dynaconf/vendor/box/box.py", line 341, in __getitem__
    raise BoxKeyError(str(err)) from None
dynaconf.vendor.box.exceptions.BoxKeyError: "'dynaconf_merge_unique'"

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "config.py", line 10, in <module>
    print(settings.as_dict())
  File "/Users/nix/Dev/dynaconf/dynaconf/base.py", line 122, in __getattr__
    self._setup()
  File "/Users/nix/Dev/dynaconf/dynaconf/base.py", line 183, in _setup
    self._wrapped = self._wrapper_class(
  File "/Users/nix/Dev/dynaconf/dynaconf/base.py", line 271, in __init__
    self.execute_loaders()
  File "/Users/nix/Dev/dynaconf/dynaconf/base.py", line 1160, in execute_loaders
    settings_loader(
  File "/Users/nix/Dev/dynaconf/dynaconf/loaders/__init__.py", line 284, in settings_loader
    loader["loader"].load(
  File "/Users/nix/Dev/dynaconf/dynaconf/loaders/yaml_loader.py", line 96, in load
    loader.load(
  File "/Users/nix/Dev/dynaconf/dynaconf/loaders/base.py", line 83, in load
    self._envless_load(source_data, silent, key)
  File "/Users/nix/Dev/dynaconf/dynaconf/loaders/base.py", line 124, in _envless_load
    self._set_data_to_obj(
  File "/Users/nix/Dev/dynaconf/dynaconf/loaders/base.py", line 210, in _set_data_to_obj
    self.obj.update(
  File "/Users/nix/Dev/dynaconf/dynaconf/base.py", line 1060, in update
    self.set(
  File "/Users/nix/Dev/dynaconf/dynaconf/base.py", line 994, in set
    parsed, source_metadata = self._merge_before_set(
  File "/Users/nix/Dev/dynaconf/dynaconf/base.py", line 1103, in _merge_before_set
    value = object_merge(existing, value)
  File "/Users/nix/Dev/dynaconf/dynaconf/utils/__init__.py", line 104, in object_merge
    handle_metavalues(old, new)
  File "/Users/nix/Dev/dynaconf/dynaconf/utils/__init__.py", line 169, in handle_metavalues
    "dynaconf_merge", new[key].pop("dynaconf_merge_unique", None)
  File "/Users/nix/Dev/dynaconf/dynaconf/vendor/box/box.py", line 430, in pop
    item = self[key]
  File "/Users/nix/Dev/dynaconf/dynaconf/utils/boxing.py", line 21, in evaluate
    value = f(dynabox, item, *args, **kwargs)
  File "/Users/nix/Dev/dynaconf/dynaconf/utils/boxing.py", line 51, in __getitem__
    n_item = find_the_correct_casing(item, self) or item
  File "/Users/nix/Dev/dynaconf/dynaconf/utils/__init__.py", line 476, in find_the_correct_casing
    if k.lower() == key.lower():
AttributeError: 'int' object has no attribute 'lower'

Edit: was able to reproduce without the "exclude" key, so I changed the example.
Edit 2: was able to reproduce with an even simple example. Maybe it's expected?

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions