micropython-structured-config

Minimal read-only interface to https://gitlab.com/alelec/structured_config for micropython supporting json backend

Moderate Pure Nim score 35/100 · last commit 2026-01-21 · 1 stars · tests present · no docs generated

Summary

Latest Version Unknown
License Unknown
CI Status Failing
Stars 1
Forks 2
Open Issues 0
Last Commit 2026-01-21
Downloads 0
Last Indexed 2026-07-31 04:42

Installation

nimble install micropython-structured-config
choosenim install micropython-structured-config
git clone https://gitlab.com/alelec/micropython-structured-config

OS Compatibility

Platform Linux macOS Windows FreeBSD OpenBSD NetBSD Android iOS WASM Embedded
micropython-structured-config - - - - - - -

README

Structured Config for Micropython

A configuration module for python where the config structure is solely defined in python with automatic reading & writing to disk and field validation.

This package provides a micropython port of https://gitlab.com/alelec/structured_config with support for json storage files.

Background

There are lots of different modules and formats available for creating configuration files in a python project.

All of the ones I've used in the past have one main limitations in common however; the primary definition of the configuration elements it either not written in python, or it's written in something like a python dict where you don't get particularly good static inspection of elements.

I personally like to do my python development in a smart ide like pycharm where I can take full advantage of inspection and auto-completion. If your config is not written in python however, I don't get to do this.

If you want any kind of introspection of config files, you end up having some kind of python parser of the config file with all the configuration elements repeated in both the default template and in some kind of mirror class. This module aims to remove this limitation.

Requirements

structured_config depends on some features included in micropython v1.13 so you'll want to be using that at a minimum.

It also needs the MICROPY_PY_DELATTR_SETATTR build setting enabled. This is included by default on stm32 port, but for other ports you will need a custom build with this enabled.

Basic Usage

With structured_config, your config.py file in your project can be something like:

::

from structured_config import ConfigFile, Structure

class Config(Structure):

    class server(Structure):
        url = 'https:www.example.com'
        username = '<user>'
        password = '<password>'


    # Max number of tcp connections at any one time
    concurrent_connections =  32

    # Local service port
    service_port = 45080


config = Config('/path/to/config.json')

Any other modules in your project can then simply

::

from config import config

import requests
from requests.auth import HTTPBasicAuth

r = requests.get(config.server.url, auth=HTTPBasicAuth(config.server.username, config.server.password))

and so on. Your IDE should give you full autocomplete on all these elements, becuase as far as it knows your config is a normal class with normal static attributes. If you want to change these config items in code it's as simple as setting the attribute

::

from config import config

config.concurrent_connections = 64

config.__save__()

That's it. The config is written to disk in the json file pointed to in Config() instantiation

Lists of elements

If you want a slightly more complex config file with a list of elements, this can be handled too

::

import structured_config
from structured_config import Structure, ConfigFile

# Pre-define the object we want to store a list of.
class Map(Structure):
    remote_path = None
    local_path = None


# Default configuration for the application
class Config(Structure):

    class server(Structure):
        url = 'https:www.example.com'
        username = '<user>'
        password = '<password>'

    mapping = [
        Map(
            remote_path="/test/",
            local_path="~/test/"
        ),
        Map(
            remote_path="/one/",
            local_path="~/two/"
        ),
        Map(
            remote_path="/two/",
            local_path="~/one/"
        )
    ]

config = Config('config.json')

Your main code can access the Map items in the list by all the normal means. if you append() new ones onto the list or pop() old ones off the list, the config will automatically write them to disk. Same goes for editing either of the attributes in any of the Map objects that have been added to the list.

The type of element added to the list can be enforced / validated too, eg

::

import structured_config
from structured_config import Structure, ConfigFile, List

# Pre-define the object we want to store a list of.
class Map(Structure):
    remote_path = None
    local_path = None


# Default configuration for the application
class Config(Structure):

    class server(Structure):
        url = 'https:www.example.com'
        username = '<user>'
        password = '<password>'

    mapping = List([
        Map(
            remote_path="/test/",
            local_path="~/test/"
        ),
        Map(
            remote_path="/one/",
            local_path="~/two/"
        ),
        Map(
            remote_path="/two/",
            local_path="~/one/"
        )
    ], type=Map)

config = Config('config.json')

Now when creating a new instance, loading from file or even just appending to the list, the type will be checked to ensure it matches the declaration.

Dictionaries of elements

Similar to the List above, a Dict of elements can be defined where the type of the values in the dict can be controlled

::

import structured_config
from structured_config import Structure, ConfigFile, Dict

# Pre-define the object we want to store a list of.
class Map(Structure):
    remote_path = None
    local_path = None

# Default configuration for the application
class Config(Structure):

    mapping = Dict({
        "test": Map(remote_path="/test/", local_path="~/test/"),
        }, type=Map)

config = Config('config.json')
config.mapping['new'] = Map(remote_path='c:\\new', local_path='~/new')

# Will raise an exception as the value is incorrect!
config.mapping['fails'] = "Nope"

Format convertions and validations

If you want to enforce the type of some attributes, we've got that covered as well:

::

from structured_config import ConfigFile, Structure, TypedField, IntField

class config(Structure):

    concurrent_connections = IntField(32)

    path = TypedField('$HOME', os.path.expandvars)


config = Config('config.json')

Some examples of available TypeFields include: * IntField : converts to int() * FloatField : converts to float() * StrField : converts to str() * PathField : converts to pathlib.Path()

Others can be created on demand by using TypeField(value, converter_funtion) or by subclassing TypeField as per the ones above.

Any time a config attribute is set, it will be passed through the validation function first. The raw (unconverted) value will be saved to disk.

Get's on the config objects attribute return the converted value, not the Field object.

Field documentation

Once you're using Field() types to define your elements you can document them too :

::

from structured_config import ConfigFile, Structure, TypedField, IntField

class config(Structure):

    concurrent_connections = IntField(32)            | "The number of connections allowed"
    path = TypedField('$HOME', os.path.expandvars)   | "User's home directory"


config = Config('config.json')

These can be accessed in code via Config.__fdoc__('concurrent_connections')