Skip to content

Commit

Permalink
2.0.0rc3
Browse files Browse the repository at this point in the history
  • Loading branch information
omry committed Jan 4, 2020
1 parent df9d55e commit c74626a
Show file tree
Hide file tree
Showing 38 changed files with 1,179 additions and 942 deletions.
3 changes: 3 additions & 0 deletions .isort.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ include_trailing_comma=True
force_grid_wrap=0
use_parentheses=True
line_length=88
ensure_newline_before_comments=True
known_third_party=omegaconf,ray,pytest
known_first_party=hydra,hydra_plugins
7 changes: 4 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ repos:
language: system
entry: flake8
types: [python]
- repo: https://github.com/pre-commit/mirrors-isort
rev: '' # Use the revision sha / tag you want to point at
# isort to ensure imports remains sorted
- repo: https://github.com/timothycrosley/isort
rev: 'c54b3dd'
hooks:
- id: isort
- id: isort
22 changes: 11 additions & 11 deletions docs/source/structured_config.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Two types of structures classes that are supported: dataclasses and attr classes

This documentation will use dataclasses, but you can use the annotation `@attr.s(auto_attribs=True)` from attrs instead of `@dataclass`.

Basic usage involves passing in a structured config class or instance to OmegaConf.create(), which will return an OmegaConf config that matches
Basic usage involves passing in a structured config class or instance to OmegaConf.structured(), which will return an OmegaConf config that matches
the values and types specified in the input. OmegaConf will validate modifications to the created config object at runtime against the schema specified
in the input class.

Expand Down Expand Up @@ -58,8 +58,8 @@ fields during construction.

.. doctest::

>>> conf1 = OmegaConf.create(SimpleTypes)
>>> conf2 = OmegaConf.create(SimpleTypes())
>>> conf1 = OmegaConf.structured(SimpleTypes)
>>> conf2 = OmegaConf.structured(SimpleTypes())
>>> # The two configs are identical in this case
>>> assert conf1 == conf2
>>> # But the second form allow for easy customization of the values:
Expand All @@ -80,7 +80,7 @@ Configs in struct mode rejects attempts to access or set fields that are not alr

.. doctest::

>>> conf = OmegaConf.create(SimpleTypes)
>>> conf = OmegaConf.structured(SimpleTypes)
>>> with raises(KeyError):
... conf.does_not_exist

Expand All @@ -91,7 +91,7 @@ Python type annotation can be used by static type checkers like Mypy/Pyre or by

.. doctest::

>>> conf: SimpleTypes = OmegaConf.create(SimpleTypes)
>>> conf: SimpleTypes = OmegaConf.structured(SimpleTypes)
>>> # passes static type checking
>>> assert conf.description == "text"
>>> with raises(ValidationError):
Expand Down Expand Up @@ -155,7 +155,7 @@ Structured configs can be nested.
... # You can also specify different defaults for nested classes
... manager: User = User(name="manager", height=Height.TALL)

>>> conf : Group = OmegaConf.create(Group)
>>> conf : Group = OmegaConf.structured(Group)
>>> print(conf.pretty())
admin:
height: ???
Expand Down Expand Up @@ -200,7 +200,7 @@ OmegaConf verifies at runtime that your Lists contains only values of the correc

.. doctest::

>>> conf : Lists = OmegaConf.create(Lists)
>>> conf : Lists = OmegaConf.structured(Lists)

>>> # Okay, 10 is an int
>>> conf.ints.append(10)
Expand Down Expand Up @@ -232,7 +232,7 @@ OmegaConf supports field modifiers such as MISSING and Optional.
... optional_num: Optional[int] = 10
... another_num: int = MISSING

>>> conf : Modifiers = OmegaConf.create(Modifiers)
>>> conf : Modifiers = OmegaConf.structured(Modifiers)

Mandatory missing values
^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down Expand Up @@ -283,7 +283,7 @@ To work around it, use SI and II described below.
... # wrapped with ${} automatically.
... c: int = II("val")

>>> conf : Interpolation = OmegaConf.create(Interpolation)
>>> conf : Interpolation = OmegaConf.structured(Interpolation)
>>> assert conf.a == 100
>>> assert conf.b == 100
>>> assert conf.c == 100
Expand All @@ -301,7 +301,7 @@ Frozen dataclasses and attr classes are supported via OmegaConf :ref:`read-only-
... x: int = 10
... list: List = field(default_factory=lambda: [1, 2, 3])

>>> conf = OmegaConf.create(FrozenClass)
>>> conf = OmegaConf.structured(FrozenClass)
>>> with raises(ReadonlyConfigError):
... conf.x = 20

Expand Down Expand Up @@ -349,7 +349,7 @@ This will cause a validation error when merging the config from the file with th

.. doctest::

>>> schema = OmegaConf.create(MyConfig)
>>> schema = OmegaConf.structured(MyConfig)
>>> conf = OmegaConf.load("source/example.yaml")
>>> with raises(ValidationError):
... OmegaConf.merge(schema, conf)
Expand Down
5 changes: 3 additions & 2 deletions docs/source/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ See :doc:`structured_config` for more details, or keep reading for a minimal exa
... class MyConfig:
... port: int = 80
... host: str = "localhost"
>>> conf = OmegaConf.create(MyConfig)
>>> # For strict typing purposes, prefer OmegaConf.structured() when creating structured configs
>>> conf = OmegaConf.structured(MyConfig)
>>> print(conf.pretty())
host: localhost
port: 80
Expand All @@ -161,7 +162,7 @@ You can use an object to initialize the config as well:

.. doctest::

>>> conf = OmegaConf.create(MyConfig(port=443))
>>> conf = OmegaConf.structured(MyConfig(port=443))
>>> print(conf.pretty())
host: localhost
port: 443
Expand Down
1 change: 1 addition & 0 deletions news/114.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DictConfig and ListConfig now implements typing.MutableMapping and typing.MutableSequence.
8 changes: 3 additions & 5 deletions noxfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ def coverage(session):
session.run("pip", "install", ".[coverage]", silent=True)
session.run("coverage", "erase")
session.run("coverage", "run", "--append", "-m", "pytest", silent=True)
# Increase the fail_under as coverage improves
session.run("coverage", "report", "--fail-under=95")
session.run("coverage", "report", "--fail-under=100")
# report to coveralls
session.run("coveralls", success_codes=[0, 1])

Expand All @@ -53,10 +52,9 @@ def lint(session):
# if this fails you need to format your code with black
session.run("black", "--check", ".")

session.run("mypy", "tests")
session.run("mypy", "omegaconf", "--strict")
session.run("mypy", ".", "--strict")

session.run("isort", "--check")
session.run("isort", ".", "--check")


@nox.session(python=PYTHON_VERSIONS)
Expand Down
17 changes: 13 additions & 4 deletions omegaconf/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from .base import Node
from .basecontainer import BaseContainer
from .base import Container, Node
from .dictconfig import DictConfig
from .errors import (
MissingMandatoryValue,
Expand All @@ -18,7 +17,16 @@
StringNode,
ValueNode,
)
from .omegaconf import II, MISSING, SI, OmegaConf, flag_override, open_dict, read_write
from .omegaconf import (
II,
MISSING,
SI,
OmegaConf,
Resolver,
flag_override,
open_dict,
read_write,
)
from .version import __version__

__all__ = [
Expand All @@ -28,10 +36,11 @@
"ReadonlyConfigError",
"UnsupportedValueType",
"UnsupportedKeyType",
"BaseContainer",
"Container",
"ListConfig",
"DictConfig",
"OmegaConf",
"Resolver",
"flag_override",
"read_write",
"open_dict",
Expand Down
21 changes: 20 additions & 1 deletion omegaconf/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@

try:
import dataclasses

except ImportError: # pragma: no cover
dataclasses = None # type: ignore # pragma: no cover

try:
import attr

except ImportError: # pragma: no cover
attr = None # type: ignore # pragma: no cover

Expand Down Expand Up @@ -261,10 +263,11 @@ def is_int(st: str) -> bool:

# noinspection PyProtectedMember
def _re_parent(node: Node) -> None:
from .listconfig import ListConfig
from .dictconfig import DictConfig
from .listconfig import ListConfig

# update parents of first level Config nodes to self

assert isinstance(node, Node)
if isinstance(node, DictConfig):
for _key, value in node.__dict__["content"].items():
Expand All @@ -274,3 +277,19 @@ def _re_parent(node: Node) -> None:
for item in node.__dict__["content"]:
item._set_parent(node)
_re_parent(item)


def is_primitive_list(obj: Any) -> bool:
from .base import Container

return not isinstance(obj, Container) and isinstance(obj, (list, tuple))


def is_primitive_dict(obj: Any) -> bool:
from .base import Container

return not isinstance(obj, Container) and isinstance(obj, (dict))


def is_primitive_container(obj: Any) -> bool:
return is_primitive_list(obj) or is_primitive_dict(obj)
50 changes: 46 additions & 4 deletions omegaconf/base.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from abc import ABC
from typing import Optional
from abc import ABC, abstractmethod
from typing import Any, Iterator, Optional, Union


class Node(ABC):
Expand All @@ -12,7 +12,7 @@ def __init__(self, parent: Optional["Node"]):
# set to false: flag is false
self.__dict__["flags"] = {}

def _set_parent(self, parent: "Container") -> None:
def _set_parent(self, parent: Optional["Container"]) -> None:
assert parent is None or isinstance(parent, Container)
self.__dict__["parent"] = parent

Expand Down Expand Up @@ -60,4 +60,46 @@ class Container(Node):
Container tagging interface
"""

pass
@abstractmethod
def pretty(self, resolve: bool = False) -> str:
... # pragma: no cover

@abstractmethod
def update_node(self, key: str, value: Any = None) -> None:
... # pragma: no cover

@abstractmethod
def select(self, key: str) -> Any:
... # pragma: no cover

@abstractmethod
def __delitem__(self, key: Union[str, int, slice]) -> None:
... # pragma: no cover

@abstractmethod
def __setitem__(self, key: Any, value: Any) -> None:
... # pragma: no cover

@abstractmethod
def get_node(self, key: Any) -> Node:
... # pragma: no cover

@abstractmethod
def __eq__(self, other: Any) -> bool:
... # pragma: no cover

@abstractmethod
def __ne__(self, other: Any) -> bool:
... # pragma: no cover

@abstractmethod
def __hash__(self) -> int:
... # pragma: no cover

@abstractmethod
def __iter__(self) -> Iterator[str]:
... # pragma: no cover

@abstractmethod
def __getitem__(self, key_or_index: Any) -> Any:
... # pragma: no cover
Loading

0 comments on commit c74626a

Please sign in to comment.