nebius/SWE-bench-extra huggingface dataset:
Repository: omry/omegaconf

Issue:
[bug] Env Interpolation doesn't respect paths
```py
from omegaconf import OmegaConf
a = OmegaConf.create({"a": {"b": "${env:DATASET_CONFIG,configs/datasets}"}})
print(a.a.b) # prints '${env:DATASET_CONFIG,configs/datasets}'
```

Should print configs/datasets

Version: 2.0.0.rc24

Comments:

Patch:
diff --git a/omegaconf/_utils.py b/omegaconf/_utils.py
index 8c7a6e4..126fca1 100644
--- a/omegaconf/_utils.py
+++ b/omegaconf/_utils.py
@@ -258,7 +258,7 @@ def get_value_kind(value: Any, return_match_list: bool = False) -> Any:
     """
 
     key_prefix = r"\${(\w+:)?"
-    legal_characters = r"([\w\.%_ \\,-]*?)}"
+    legal_characters = r"([\w\.%_ \\/:,-]*?)}"
     match_list: Optional[List[Match[str]]] = None
 
     def ret(


Test patch:
diff --git a/tests/test_interpolation.py b/tests/test_interpolation.py
index eb57d8d..6be772d 100644
--- a/tests/test_interpolation.py
+++ b/tests/test_interpolation.py
@@ -147,13 +147,20 @@ def test_env_interpolation_not_found() -> None:
         c.path
 
 
-def test_env_default_interpolation_missing_env() -> None:
+def test_env_default_str_interpolation_missing_env() -> None:
     if os.getenv("foobar") is not None:
         del os.environ["foobar"]
     c = OmegaConf.create({"path": "/test/${env:foobar,abc}"})
     assert c.path == "/test/abc"
 
 
+def test_env_default_interpolation_missing_env_default_with_slash() -> None:
+    if os.getenv("foobar") is not None:
+        del os.environ["foobar"]
+    c = OmegaConf.create({"path": "${env:DATA_PATH,a/b}"})
+    assert c.path == "a/b"
+
+
 def test_env_default_interpolation_env_exist() -> None:
     os.environ["foobar"] = "1234"
     c = OmegaConf.create({"path": "/test/${env:foobar,abc}"})
diff --git a/tests/test_utils.py b/tests/test_utils.py
index 74cb297..06ede88 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -202,6 +202,10 @@ class Dataclass:
         ("???", _utils.ValueKind.MANDATORY_MISSING),
         ("${foo.bar}", _utils.ValueKind.INTERPOLATION),
         ("ftp://${host}/path", _utils.ValueKind.STR_INTERPOLATION),
+        ("${func:foo}", _utils.ValueKind.INTERPOLATION),
+        ("${func:a/b}", _utils.ValueKind.INTERPOLATION),
+        ("${func:c:\\a\\b}", _utils.ValueKind.INTERPOLATION),
+        ("${func:c:\\a\\b}", _utils.ValueKind.INTERPOLATION),
     ],
 )
 def test_value_kind(value: Any, kind: _utils.ValueKind) -> None:
Repository: omry/omegaconf

Issue:
Creating a DictConfig from another drops node types
test:

```
@dataclass
class User:
    name: str
    age: int

cfg1 = OmegaConf.create(module.User(name="James Bond", age=7))
with pytest.raises(ValidationError):
  cfg1.age = "not a number"

cfg2 = OmegaConf.create(cfg1)
with pytest.raises(ValidationError):
  cfg2.age = "not a number"
```

Comments:

Patch:
diff --git a/news/252.bugix b/news/252.bugix
new file mode 100644
index 0000000..3aade21
--- /dev/null
+++ b/news/252.bugix
@@ -0,0 +1,1 @@
+Fix DictConfig created from another DictConfig drops node types
diff --git a/omegaconf/dictconfig.py b/omegaconf/dictconfig.py
index 5499a5b..aef92ee 100644
--- a/omegaconf/dictconfig.py
+++ b/omegaconf/dictconfig.py
@@ -552,7 +552,7 @@ class DictConfig(BaseContainer, MutableMapping[str, Any]):
                 self._metadata.object_type = get_type_of(value)
             elif isinstance(value, DictConfig):
                 self._metadata.object_type = dict
-                for k, v in value.items_ex(resolve=False):
+                for k, v in value.__dict__["_content"].items():
                     self.__setitem__(k, v)
                 self.__dict__["_metadata"] = copy.deepcopy(value._metadata)
 


Test patch:
diff --git a/tests/structured_conf/test_structured_config.py b/tests/structured_conf/test_structured_config.py
index 73d446d..25b9f73 100644
--- a/tests/structured_conf/test_structured_config.py
+++ b/tests/structured_conf/test_structured_config.py
@@ -800,3 +800,13 @@ class TestDictSubclass:
             module: Any = import_module(class_type)
             with pytest.raises(KeyValidationError):
                 OmegaConf.structured(module.DictSubclass.Error.User2Str())
+
+    def test_construct_from_another_retain_node_types(self, class_type: str) -> None:
+        module: Any = import_module(class_type)
+        cfg1 = OmegaConf.create(module.User(name="James Bond", age=7))
+        with pytest.raises(ValidationError):
+            cfg1.age = "not a number"
+
+        cfg2 = OmegaConf.create(cfg1)
+        with pytest.raises(ValidationError):
+            cfg2.age = "not a number"
Repository: omry/omegaconf

Issue:
open_dict change value to the inherited value
for a nested config:
```yaml
foo:
  bar:
    baz: 10
```
if foo is struct, and we do
```python
with open_dict(cfg.foo.bar):
   bar.baz = 20
```

the struct flag of foo.bar would be changed to True.

Comments:

Patch:
diff --git a/omegaconf/config.py b/omegaconf/config.py
index 0a8995d..a1b3f14 100644
--- a/omegaconf/config.py
+++ b/omegaconf/config.py
@@ -83,6 +83,13 @@ class Config(object):
         assert value is None or isinstance(value, bool)
         self.__dict__['flags'][flag] = value
 
+    def _get_node_flag(self, flag):
+        """
+        :param flag: flag to inspect
+        :return: the state of the flag on this node.
+        """
+        return self.__dict__['flags'][flag]
+
     def _get_flag(self, flag):
         """
         Returns True if this config node flag is set
diff --git a/omegaconf/omegaconf.py b/omegaconf/omegaconf.py
index 03e908b..df3a92b 100644
--- a/omegaconf/omegaconf.py
+++ b/omegaconf/omegaconf.py
@@ -228,7 +228,8 @@ def flag_override(config, name, value):
 # noinspection PyProtectedMember
 @contextmanager
 def read_write(config):
-    prev_state = OmegaConf.is_readonly(config)
+    # noinspection PyProtectedMember
+    prev_state = config._get_node_flag("readonly")
     try:
         OmegaConf.set_readonly(config, False)
         yield config
@@ -238,7 +239,8 @@ def read_write(config):
 
 @contextmanager
 def open_dict(config):
-    prev_state = OmegaConf.is_struct(config)
+    # noinspection PyProtectedMember
+    prev_state = config._get_node_flag("struct")
     try:
         OmegaConf.set_struct(config, False)
         yield config


Test patch:
diff --git a/tests/test_base_config.py b/tests/test_base_config.py
index 713ff52..b7112ed 100644
--- a/tests/test_base_config.py
+++ b/tests/test_base_config.py
@@ -275,3 +275,19 @@ def test_struct_override(src, func, expectation):
     with does_not_raise():
         with open_dict(c):
             func(c)
+
+
+@pytest.mark.parametrize("flag_name,ctx", [("struct", open_dict), ("readonly", read_write)])
+def test_open_dict_restore(flag_name, ctx):
+    """
+    Tests that internal flags are restored properly when applying context on a child node
+    """
+    cfg = OmegaConf.create({"foo": {"bar": 10}})
+    cfg._set_flag(flag_name, True)
+    assert cfg._get_node_flag(flag_name)
+    assert not cfg.foo._get_node_flag(flag_name)
+    with ctx(cfg.foo):
+        cfg.foo.bar = 20
+    assert cfg._get_node_flag(flag_name)
+    assert not cfg.foo._get_node_flag(flag_name)
+
Repository: omry/omegaconf

Issue:
Handle dotlist override with values containing =
See https://github.com/facebookresearch/hydra/issues/266 (Which is actually one bug in Hydra and one in OmegaConf).

Comments:

Patch:
diff --git a/omegaconf/config.py b/omegaconf/config.py
index 6b53109..3c80734 100644
--- a/omegaconf/config.py
+++ b/omegaconf/config.py
@@ -244,12 +244,15 @@ class Config(object):
 
     def merge_with_dotlist(self, dotlist):
         for arg in dotlist:
-            args = arg.split("=")
-            key = args[0]
-            value = None
-            if len(args) > 1:
-                # load with yaml to get correct automatic typing with the same rules as yaml parsing
-                value = yaml.load(args[1], Loader=get_yaml_loader())
+            idx = arg.find("=")
+            if idx == -1:
+                key = arg
+                value = None
+            else:
+                key = arg[0:idx]
+                value = arg[idx + 1 :]
+                value = yaml.load(value, Loader=get_yaml_loader())
+
             self.update(key, value)
 
     def update(self, key, value=None):


Test patch:
diff --git a/tests/test_update.py b/tests/test_update.py
index 0ade637..12fcacf 100644
--- a/tests/test_update.py
+++ b/tests/test_update.py
@@ -1,5 +1,6 @@
 import sys
 
+import pytest
 from pytest import raises
 
 from omegaconf import MissingMandatoryValue
@@ -154,10 +155,18 @@ def test_update_list_make_dict():
     assert c[1].b.b == "bb"
 
 
-def test_merge_with_dotlist():
-    c = OmegaConf.create([1, 2, 3])
-    c.merge_with_dotlist(["0=bar", "2.a=100"])
-    assert c == ["bar", 2, dict(a=100)]
+@pytest.mark.parametrize(
+    "cfg,overrides,expected",
+    [
+        ([1, 2, 3], ["0=bar", "2.a=100"], ["bar", 2, dict(a=100)]),
+        ({}, ["foo=bar", "bar=100"], {"foo": "bar", "bar": 100}),
+        ({}, ["foo=bar=10"], {"foo": "bar=10"}),
+    ],
+)
+def test_merge_with_dotlist(cfg, overrides, expected):
+    c = OmegaConf.create(cfg)
+    c.merge_with_dotlist(overrides)
+    assert c == expected
 
 
 def test_merge_with_cli():
Repository: omry/omegaconf

Issue:
consider implementing + operator for ListConfig

Comments:

Patch:
diff --git a/omegaconf/listconfig.py b/omegaconf/listconfig.py
index 6969aab..d2696b5 100644
--- a/omegaconf/listconfig.py
+++ b/omegaconf/listconfig.py
@@ -207,3 +207,10 @@ class ListConfig(Config):
                 return v
 
         return MyItems(self.content)
+
+    def __add__(self, o):
+        # res is sharing this list's parent to allow interpolation to work as expected
+        res = ListConfig(parent=self.__dict__["parent"], content=[])
+        res.extend(self)
+        res.extend(o)
+        return res


Test patch:
diff --git a/tests/test_basic_ops_list.py b/tests/test_basic_ops_list.py
index a97aecb..d2e5a86 100644
--- a/tests/test_basic_ops_list.py
+++ b/tests/test_basic_ops_list.py
@@ -373,3 +373,27 @@ def test_hash():
     assert hash(c1) == hash(c2)
     c2[0] = 20
     assert hash(c1) != hash(c2)
+
+
+@pytest.mark.parametrize(
+    "list1, list2, expected",
+    [
+        ([], [], []),
+        ([1, 2], [3, 4], [1, 2, 3, 4]),
+        (["x", 2, "${0}"], [5, 6, 7], ["x", 2, "x", 5, 6, 7]),
+    ],
+)
+class TestListAdd:
+    def test_list_plus(self, list1, list2, expected):
+        list1 = OmegaConf.create(list1)
+        list2 = OmegaConf.create(list2)
+        expected = OmegaConf.create(expected)
+        ret = list1 + list2
+        assert ret == expected
+
+    def test_list_plus_eq(self, list1, list2, expected):
+        list1 = OmegaConf.create(list1)
+        list2 = OmegaConf.create(list2)
+        expected = OmegaConf.create(expected)
+        list1 += list2
+        assert list1 == expected
Repository: omry/omegaconf

Issue:
Error expanding an DictConfig in pycharm debugger
OmegaConf.create(dict(foo={}))

expanding foo results in a stack trace in the debugger.


Comments:

Patch:
diff --git a/news/40.bugfix b/news/40.bugfix
new file mode 100644
index 0000000..8163863
--- /dev/null
+++ b/news/40.bugfix
@@ -0,0 +1,1 @@
+Fix an error when expanding an empty dictionary in PyCharm debugger
diff --git a/omegaconf/dictconfig.py b/omegaconf/dictconfig.py
index 5b35776..9f81527 100644
--- a/omegaconf/dictconfig.py
+++ b/omegaconf/dictconfig.py
@@ -68,6 +68,10 @@ class DictConfig(Config):
         :param key:
         :return:
         """
+        # PyCharm is sometimes inspecting __members__. returning None or throwing is
+        # confusing it and it prints an error when inspecting this object.
+        if key == "__members__":
+            return {}
         return self.get(key=key, default_value=None)
 
     def __getitem__(self, key):


Test patch:
diff --git a/tests/test_basic_ops_dict.py b/tests/test_basic_ops_dict.py
index 55af782..d968908 100644
--- a/tests/test_basic_ops_dict.py
+++ b/tests/test_basic_ops_dict.py
@@ -391,3 +391,9 @@ def test_get_with_default_from_struct_not_throwing():
     c = OmegaConf.create(dict(a=10, b=20))
     OmegaConf.set_struct(c, True)
     assert c.get("z", "default") == "default"
+
+
+def test_members():
+    # Make sure accessing __members__ does not return None or throw.
+    c = OmegaConf.create({"foo": {}})
+    assert c.__members__ == {}
Repository: omry/omegaconf

Issue:
Disable automatic conversion of date strings in from_dotlist
### Issue
When instantiating OmegaConf from `from_dotlist`, yaml loader tries to convert date-formatted strings into `date` type, therefore raises error when validating the type of values.

```
 OmegaConf.from_dotlist(["my_date=2019-11-11"])

>>>

.../site-packages/omegaconf/config.py in _prepare_value_to_add(self, key, value)
    448         if not Config.is_primitive_type(value):
    449             full_key = self.get_full_key(key)
--> 450             raise ValueError("key {}: {} is not a primitive type".format(full_key, type(value).__name__))
    451
    452         if self._get_flag('readonly'):

ValueError: key my_date: date is not a primitive type
```
This error also blocks the overriding of configuration values by using cli arguments in hydra.

### Potential workaround
Could be solved by removing implicit timestamp resolvers in default `yaml.SafeLoader`.
(Related stackoverflow: https://stackoverflow.com/questions/34667108/ignore-dates-and-times-while-parsing-yaml)




Comments:

Patch:
diff --git a/news/95.bugfix b/news/95.bugfix
new file mode 100644
index 0000000..4a99b51
--- /dev/null
+++ b/news/95.bugfix
@@ -0,0 +1,1 @@
+Disable automatic conversion of date strings in yaml decoding
\ No newline at end of file
diff --git a/omegaconf/config.py b/omegaconf/config.py
index 0d76e38..8b21e27 100644
--- a/omegaconf/config.py
+++ b/omegaconf/config.py
@@ -39,6 +39,14 @@ def get_yaml_loader():
         ),
         list(u"-+0123456789."),
     )
+    loader.yaml_implicit_resolvers = {
+        key: [
+            (tag, regexp)
+            for tag, regexp in resolvers
+            if tag != u"tag:yaml.org,2002:timestamp"
+        ]
+        for key, resolvers in loader.yaml_implicit_resolvers.items()
+    }
     return loader
 
 


Test patch:
diff --git a/tests/test_create.py b/tests/test_create.py
index 5d11d5d..668181d 100644
--- a/tests/test_create.py
+++ b/tests/test_create.py
@@ -50,7 +50,15 @@ def test_cli_passing():
 
 
 @pytest.mark.parametrize(
-    "input_, expected", [(["a=1", "b.c=2"], dict(a=1, b=dict(c=2)))]
+    "input_, expected",
+    [
+        # simple
+        (["a=1", "b.c=2"], dict(a=1, b=dict(c=2))),
+        # string
+        (["a=hello", "b=world"], dict(a="hello", b="world")),
+        # date-formatted string
+        (["my_date=2019-12-11"], dict(my_date="2019-12-11")),
+    ],
 )
 def test_dotlist(input_, expected):
     c = OmegaConf.from_dotlist(input_)