bwindsor / typed-config

Typed, extensible, dependency free configuration reader for Python projects for multiple config sources and working well in IDEs for great autocomplete performance.
MIT License
25 stars 6 forks source link

Add sections dynamically #1

Closed mishal closed 3 years ago

mishal commented 4 years ago

Hi,

I'm building an API for application extensions and I would like to add sections to the root config dynamically. Each extension of the application can add a section for itself to the main config section. Somethig like:

from typedconfig import Config, key, group_key, section
from typedconfig.source import IniFileConfigSource, ConfigSource

class RootConfig(Config):

    def register_section(self, section):
        s = section()
        # this is needed to get the section name, could you provide an attribute with the section name?
        setattr(RootConfig, s._section_name, group_key(section))

@section('extension1')
class Extension1Section(Config):
    api_key = key(cast=str)

@section('database')
class DatabaseSection(Config):
    host = key(cast=str)
    port = key(cast=int)

root = RootConfig()
root.add_source(IniFileConfigSource("local.conf"))

def register_extension1(root):
    root.register_section(DatabaseSection)
    root.add_source(IniFileConfigSource("database_default.conf"))

def register_extension2(root):
    root.register_section(Extension1Section)
    root.add_source(IniFileConfigSource("ext2_default.conf"))

register_extension1(root)
register_extension2(root)

root.clear_cache()
root.read()

with open("local.conf") as c:
    print(c.name)
    print(c.read())

with open("database_default.conf") as c:
    print(c.name)
    print(c.read())

with open("ext2_default.conf") as c:
    print(c.name)
    print(c.read())

print("RESULTS:")
print(root.database.host)
print(root.database.port)
print(root.extension1.api_key)

It looks like the order of adding sections and sources is essential, because the expected values are different:

local.conf
# Logging configuration

[database]
port=5433

[extension1]
api_key=123467

database_default.conf
# Logging configuration

[database]
host=localhost
port=5432

ext2_default.conf
# Logging configuration

[extension1]
api_key=12345678

RESULTS:
localhost
5432
12345678

I expect that the source local.conf will override the default values provided by extensions and the settings for port from section database and api_key from section extension1 will be returned.

I tried to add the local source as the last, but the results are the same.

Am I doing something wrong?

I'm using python 3.7

Thank you

btw great library :)

bwindsor commented 3 years ago

Hi @mishal - does #2 solve what you are trying to do?

In answer to your question, you need to add the local source first. Configuration sources are checked from first to last, and once a value is found in one of them, it stops.

bwindsor commented 3 years ago

Closing since no reply and I think #2 is also a suitable solution.