Skip to content

Commit

Permalink
api: Add several configuration related fixes (#583)
Browse files Browse the repository at this point in the history
Fixes #582

This makes the attributes of the configuration object case sensitive in order to match better the environment variables that are too.

This makes the attributes of the configuration object accept any legal Python variable name (Configuration().some_2_attribute) is valid now.

This makes non-defined attributes return None when queried instead of raising an AttributeError. This makes it easier to use the configuration object because the user won't have to check for the existence of the attribute beforehand:

if Configuration().some_attribute == "value":
    # do stuff

instead of

if hasattr(Configuration(), "some_attribute") and Configuration().some_attribute == "value":
    # do stuff
  • Loading branch information
ocelotl committed Apr 27, 2020
1 parent a832bb0 commit 5d675ee
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 15 deletions.
22 changes: 12 additions & 10 deletions opentelemetry-api/src/opentelemetry/configuration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,27 +19,27 @@
Simple configuration manager
This is a configuration manager for OpenTelemetry. It reads configuration
values from environment variables prefixed with
``OPENTELEMETRY_PYTHON_`` whose characters are only all caps and underscores.
The first character after ``OPENTELEMETRY_PYTHON_`` must be an uppercase
character.
values from environment variables prefixed with ``OPENTELEMETRY_PYTHON_`` whose
characters are only alphanumeric characters and unserscores, except for the
first character after ``OPENTELEMETRY_PYTHON_`` which must not be a number.
For example, these environment variables will be read:
1. ``OPENTELEMETRY_PYTHON_SOMETHING``
2. ``OPENTELEMETRY_PYTHON_SOMETHING_ELSE_``
3. ``OPENTELEMETRY_PYTHON_SOMETHING_ELSE_AND__ELSE``
4. ``OPENTELEMETRY_PYTHON_SOMETHING_ELSE_AND_else``
4. ``OPENTELEMETRY_PYTHON_SOMETHING_ELSE_AND_else2``
These won't:
1. ``OPENTELEMETRY_PYTH_SOMETHING``
2. ``OPENTELEMETRY_PYTHON_something``
3. ``OPENTELEMETRY_PYTHON_SOMETHING_2_AND__ELSE``
4. ``OPENTELEMETRY_PYTHON_SOMETHING_%_ELSE``
2. ``OPENTELEMETRY_PYTHON_2_SOMETHING_AND__ELSE``
3. ``OPENTELEMETRY_PYTHON_SOMETHING_%_ELSE``
The values stored in the environment variables can be found in an instance of
``opentelemetry.configuration.Configuration``. This class can be instantiated
freely because instantiating it returns a singleton.
freely because instantiating it returns always the same object.
For example, if the environment variable
``OPENTELEMETRY_PYTHON_METER_PROVIDER`` value is ``my_meter_provider``, then
Expand Down Expand Up @@ -93,11 +93,13 @@ def __new__(cls) -> "Configuration":

for key, value in environ.items():

match = fullmatch("OPENTELEMETRY_PYTHON_([A-Z][A-Z_]*)", key)
match = fullmatch(
r"OPENTELEMETRY_PYTHON_([A-Za-z_][\w_]*)", key
)

if match is not None:

key = match.group(1).lower()
key = match.group(1)

setattr(Configuration, "_{}".format(key), value)
setattr(
Expand Down
23 changes: 18 additions & 5 deletions opentelemetry-api/tests/configuration/test_configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@

class TestConfiguration(TestCase):
def setUp(self):
# This is added here to force a reload of the whole Configuration
# class, resetting its internal attributes so that each tests starts
# with a clean class.
from opentelemetry.configuration import Configuration # type: ignore

def tearDown(self):
Expand All @@ -35,27 +38,37 @@ def test_singleton(self):
{
"OPENTELEMETRY_PYTHON_METER_PROVIDER": "meter_provider",
"OPENTELEMETRY_PYTHON_TRACER_PROVIDER": "tracer_provider",
"OPENTELEMETRY_PYTHON_OThER": "other",
"OPENTELEMETRY_PYTHON_OTHER_7": "other_7",
"OPENTELEMETRY_PTHON_TRACEX_PROVIDER": "tracex_provider",
},
)
def test_environment_variables(self): # type: ignore
self.assertEqual(
Configuration().meter_provider, "meter_provider"
Configuration().METER_PROVIDER, "meter_provider"
) # pylint: disable=no-member
self.assertEqual(
Configuration().tracer_provider, "tracer_provider"
Configuration().TRACER_PROVIDER, "tracer_provider"
) # pylint: disable=no-member
self.assertEqual(
Configuration().OThER, "other"
) # pylint: disable=no-member
self.assertEqual(
Configuration().OTHER_7, "other_7"
) # pylint: disable=no-member
self.assertIsNone(Configuration().TRACEX_PROVIDER)

@patch.dict(
"os.environ", # type: ignore
{"OPENTELEMETRY_PYTHON_TRACER_PROVIDER": "tracer_provider"},
)
def test_property(self):
with self.assertRaises(AttributeError):
Configuration().tracer_provider = "new_tracer_provider"
Configuration().TRACER_PROVIDER = "new_tracer_provider"

def test_slots(self):
with self.assertRaises(AttributeError):
Configuration().xyz = "xyz" # pylint: disable=assigning-non-slot
Configuration().XYZ = "xyz" # pylint: disable=assigning-non-slot

def test_getattr(self):
Configuration().xyz is None
self.assertIsNone(Configuration().XYZ)

0 comments on commit 5d675ee

Please sign in to comment.