-
Notifications
You must be signed in to change notification settings - Fork 190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Engine configuration utility #1828
Merged
Merged
Changes from 6 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
732c5cd
Create the configuration utility
Gamenot 24cd940
Gen header.
Gamenot c8e9e29
Fix types test.
Gamenot 0589ab3
Add test.
Gamenot 1394667
Fix test types.
Gamenot 45715ba
Update config to take in file locations.
Gamenot 9296335
Ensure the ini config file is included.
Gamenot 693683d
Add missing docstring and formatting
Gamenot d43d4be
Fix ambiguity with smarts and smarts.core.smarts
Gamenot 949b640
Update documentation
Gamenot dc983c9
Update docs/sim/configuration.rst
Gamenot e577d66
Move sim configuration to next steps.
Gamenot a6ab9fc
Assign pybullet frequency to make clear.
Gamenot db8cdc9
Update docs/sim/configuration.rst
Gamenot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
# MIT License | ||
# | ||
# Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. | ||
# | ||
# Permission is hereby granted, free of charge, to any person obtaining a copy | ||
# of this software and associated documentation files (the "Software"), to deal | ||
# in the Software without restriction, including without limitation the rights | ||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
# copies of the Software, and to permit persons to whom the Software is | ||
# furnished to do so, subject to the following conditions: | ||
# | ||
# The above copyright notice and this permission notice shall be included in | ||
# all copies or substantial portions of the Software. | ||
# | ||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE | ||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
# THE SOFTWARE. | ||
import configparser | ||
import functools | ||
import os | ||
from pathlib import Path | ||
from typing import Any, Callable, Optional, Union | ||
|
||
_UNSET = object() | ||
|
||
|
||
class Config: | ||
"""A configuration utility that handles configuration from file and environment variable. | ||
|
||
Args: | ||
config_file (Union[str, Path]): The path to the configuration file. | ||
environment_prefix (str, optional): The prefix given to the environment variables. Defaults to "". | ||
|
||
Raises: | ||
FileNotFoundError: If the configuration file cannot be found at the given file location. | ||
""" | ||
|
||
def __init__( | ||
self, config_file: Union[str, Path], environment_prefix: str = "" | ||
) -> None: | ||
if isinstance(config_file, str): | ||
config_file = Path(config_file) | ||
if not config_file.is_file(): | ||
raise FileNotFoundError(f"Configuration file not found at {config_file}") | ||
|
||
self._config = configparser.ConfigParser( | ||
interpolation=configparser.ExtendedInterpolation() | ||
) | ||
self._config.read(str(config_file.absolute())) | ||
self._environment_prefix = environment_prefix.upper() | ||
self._format_string = self._environment_prefix + "_{}_{}" | ||
|
||
@property | ||
def environment_prefix(self): | ||
"""The prefix that environment variables configuration is provided with.""" | ||
return self._environment_prefix | ||
|
||
@functools.lru_cache(maxsize=100) | ||
def get_setting( | ||
self, | ||
section: str, | ||
option: str, | ||
default: Any = _UNSET, | ||
cast: Callable[[str], Any] = str, | ||
) -> Optional[Any]: | ||
"""Finds the given configuration checking the following in order: environment variable, | ||
configuration file, and default. | ||
|
||
Args: | ||
section (str): The grouping that the configuration option is under. | ||
option (str): The specific configuration option. | ||
default (Any, optional): The default if the requested configuration option is not found. Defaults to _UNSET. | ||
cast (Callable, optional): A function that takes a string and returns the desired type. Defaults to str. | ||
|
||
|
||
Returns: | ||
Optional[str]: The value of the configuration. | ||
|
||
Raises: | ||
KeyError: If the configuration option is not found in the configuration file and no default is provided. | ||
configparser.NoSectionError: If the section in the configuration file is not found and no default is provided. | ||
""" | ||
env_variable = self._format_string.format(section.upper(), option.upper()) | ||
setting = os.getenv(env_variable) | ||
if setting is not None: | ||
return cast(setting) | ||
try: | ||
value = self._config[section][option] | ||
except (configparser.NoSectionError, KeyError): | ||
if default is _UNSET: | ||
raise | ||
return default | ||
return cast(value) | ||
|
||
def __call__( | ||
self, | ||
section: str, | ||
option: str, | ||
default: Any = _UNSET, | ||
cast: Callable[[str], Any] = str, | ||
) -> Optional[Any]: | ||
return self.get_setting(section, option, default, cast) | ||
|
||
def __repr__(self) -> str: | ||
return f"Config(config_file={ {k: dict(v.items()) for k, v in self._config.items(raw=True)} }, environment_prefix={self._environment_prefix})" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
# MIT License | ||
# | ||
# Copyright (C) 2023. Huawei Technologies Co., Ltd. All rights reserved. | ||
# | ||
# Permission is hereby granted, free of charge, to any person obtaining a copy | ||
# of this software and associated documentation files (the "Software"), to deal | ||
# in the Software without restriction, including without limitation the rights | ||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
# copies of the Software, and to permit persons to whom the Software is | ||
# furnished to do so, subject to the following conditions: | ||
# | ||
# The above copyright notice and this permission notice shall be included in | ||
# all copies or substantial portions of the Software. | ||
# | ||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
# FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE | ||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
# THE SOFTWARE. | ||
import configparser | ||
import functools | ||
import os | ||
import tempfile | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
from smarts.core.configuration import Config | ||
|
||
|
||
@pytest.fixture | ||
def config_path(): | ||
config = configparser.ConfigParser() | ||
config["section_1"] = {"string_option": "value", "option_2": "value_2"} | ||
config["section_2"] = {"bool_option": "True", "float_option": "3.14"} | ||
with tempfile.TemporaryDirectory() as tmpdir: | ||
file = Path(tmpdir) / "config.ini" | ||
with file.open("w") as file_pointer: | ||
config.write(fp=file_pointer) | ||
yield str(file) | ||
|
||
|
||
def test_get_setting_with_file(config_path): | ||
config = Config(config_path) | ||
assert config.get_setting("section_1", "string_option") == "value" | ||
partition_string = functools.partial( | ||
lambda source, sep: str.partition(source, sep), sep="_" | ||
) | ||
assert config.get_setting("section_1", "option_2", cast=partition_string) == ( | ||
"value", | ||
"_", | ||
"2", | ||
) | ||
assert config.get_setting("section_2", "bool_option", cast=bool) is True | ||
assert config.get_setting("section_2", "float_option", cast=float) == 3.14 | ||
with pytest.raises(KeyError): | ||
config.get_setting("nonexistent", "option") | ||
|
||
|
||
def test_get_setting_with_environment_variables(config_path): | ||
config = Config(config_path, "smarts") | ||
assert config.get_setting("nonexistent", "option", default=None) is None | ||
|
||
os.environ["SMARTS_NONEXISTENT_OPTION"] = "now_exists" | ||
config = Config(config_path, "smarts") | ||
assert config.get_setting("nonexistent", "option", default=None) == "now_exists" | ||
del os.environ["SMARTS_NONEXISTENT_OPTION"] | ||
|
||
|
||
def test_get_missing_section_and_missing_option(): | ||
from smarts.core import config as core_conf | ||
|
||
core_conf.cache_clear() | ||
|
||
config: Config = core_conf() | ||
|
||
with pytest.raises(KeyError): | ||
config.get_setting("core", "not_a_setting") | ||
|
||
with pytest.raises(KeyError): | ||
config.get_setting("not_a_section", "bar") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
[benchmark] | ||
[core] | ||
[controllers] | ||
[physics] | ||
max_pybullet_freq = 240 | ||
[providers] | ||
[rendering] | ||
[resources] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This caused an odd bug. It could not resolve the difference between
smarts
andsmarts.core.smarts
. I believe should changesmarts.core.smarts
tosmarts.core.engine
.