A lightweight Traits like module

Overview

Traitlets

Build Status Documentation Status

home https://github.com/ipython/traitlets
pypi-repo https://pypi.org/project/traitlets/
docs https://traitlets.readthedocs.io/
license Modified BSD License

Traitlets is a pure Python library enabling:

  • the enforcement of strong typing for attributes of Python objects (typed attributes are called "traits");
  • dynamically calculated default values;
  • automatic validation and coercion of trait attributes when attempting a change;
  • registering for receiving notifications when trait values change;
  • reading configuring values from files or from command line arguments - a distinct layer on top of traitlets, so you may use traitlets without the configuration machinery.

Its implementation relies on the descriptor pattern, and it is a lightweight pure-python alternative of the traits library.

Traitlets powers the configuration system of IPython and Jupyter and the declarative API of IPython interactive widgets.

Installation

For a local installation, make sure you have pip installed and run:

pip install traitlets

For a development installation, clone this repository, change into the traitlets root directory, and run pip:

git clone https://github.com/ipython/traitlets.git
cd traitlets
pip install -e .

Running the tests

pip install "traitlets[test]"
py.test traitlets

Usage

Any class with trait attributes must inherit from HasTraits. For the list of available trait types and their properties, see the Trait Types section of the documentation.

Dynamic default values

To calculate a default value dynamically, decorate a method of your class with @default({traitname}). This method will be called on the instance, and should return the default value. In this example, the _username_default method is decorated with @default('username'):

import getpass
from traitlets import HasTraits, Unicode, default

class Identity(HasTraits):
    username = Unicode()

    @default('username')
    def _username_default(self):
        return getpass.getuser()

Callbacks when a trait attribute changes

When a trait changes, an application can follow this trait change with additional actions.

To do something when a trait attribute is changed, decorate a method with traitlets.observe(). The method will be called with a single argument, a dictionary which contains an owner, new value, old value, name of the changed trait, and the event type.

In this example, the _num_changed method is decorated with @observe(`num`):

from traitlets import HasTraits, Integer, observe

class TraitletsExample(HasTraits):
    num = Integer(5, help="a number").tag(config=True)

    @observe('num')
    def _num_changed(self, change):
        print("{name} changed from {old} to {new}".format(**change))

and is passed the following dictionary when called:

{
  'owner': object,  # The HasTraits instance
  'new': 6,         # The new value
  'old': 5,         # The old value
  'name': "foo",    # The name of the changed trait
  'type': 'change', # The event type of the notification, usually 'change'
}

Validation and coercion

Each trait type (Int, Unicode, Dict etc.) may have its own validation or coercion logic. In addition, we can register custom cross-validators that may depend on the state of other attributes. For example:

from traitlets import HasTraits, TraitError, Int, Bool, validate

class Parity(HasTraits):
    value = Int()
    parity = Int()

    @validate('value')
    def _valid_value(self, proposal):
        if proposal['value'] % 2 != self.parity:
            raise TraitError('value and parity should be consistent')
        return proposal['value']

    @validate('parity')
    def _valid_parity(self, proposal):
        parity = proposal['value']
        if parity not in [0, 1]:
            raise TraitError('parity should be 0 or 1')
        if self.value % 2 != parity:
            raise TraitError('value and parity should be consistent')
        return proposal['value']

parity_check = Parity(value=2)

# Changing required parity and value together while holding cross validation
with parity_check.hold_trait_notifications():
    parity_check.value = 1
    parity_check.parity = 1

However, we recommend that custom cross-validators don't modify the state of the HasTraits instance.

Release build:

$ pip install build
$ python -m build .
Comments
  • Cross Validation Using New Decorator API

    Cross Validation Using New Decorator API

    brief example

    
    from traitlets import HasTraits, Int, validate
    
    class H(HasTraits):
    
        i = Int()
    
        @validate('i')
        def _i_validator(self, proposal):
            return proposal['value']+1
    
    h  = H()
    h.i = 1
    print('result : '+ str(h.i))
    

    'result : 2'

    opened by rmorshea 68
  • Traitlet API

    Traitlet API

    Since Matplotlib's folks are starting to write traitlet-based APIs, we probably need to think of a roadmap for the future of the library if it is to be more widely adopted by the Scipy community.

    There are some improvements that we could easily make without splitting traitlets in two different repos:


    1. Deprecate trait attribute declaration with TraitType types instead of TraitType instances

    class Foo(HasTraits):
        bar = Int    # deprecated
        baz = Int()  # ok
        alpha = List(trait=Int)     # deprecated
        alpha = List(trait=Int())   # ok
    

    (Implemented in #51 and #55 - merged)


    2. Like in Atom, separate the metadata from the keyword arguments in TraitType's constructor.

    x = Int(allow_none=True, sync=True)      # deprecated
    x = Int(allow_none=True).tag(sync=True)  # ok
    

    (Implemented in #53 - merged)


    3. A replacement for the cumbersome on_trait_change in the future, with a more convenient signature and a simpler name.

    • We now use observe/ unobserve method instead of using a remove=True/False argument with on_trait_change.

    • observe takes 1 positional argument (the handler), and two keyword arguments, names and type.

    • The callbacks take a single change dictionary argument, containing

      {
          'owner': the HasTraits instance,
          'old': the old trait attribute value,
          'new': the new trait attribute value,
          'name': the name of the changing attribute,
      }
      
    • A new @observe decorator to register methods as trait change handlers.

    (Implemented in #61 - merged)


    4. Deprecate the custom cross-validation magic methods _*bar*_validate to the benefit of a @validate('bar') decorator.

    (Implemented in #73 - merged)


    5. Since the base trait type now inherits from BaseDescriptor and other descriptors are defined to work well with HasTraits, we could make the following changes: - rename MetaHasTraits into MetaHasDescriptors and deprecate the old name. - introduce a base class to HasTraits called HasDescriptors.

    (Implemented in #70 - merged)


    6. Deprecate the default-value initializer magic methods _*bar*_default to the benefit of a @default('bar') decorator.

    (Implemented in #114 - merged)


    7. What is the best place for a repository of extra trait types for common types in the scipy stack such as ` numpy arrays, pandas/xray data structures, and their (binary) serialization functions for widgets (or other clients of comms) and ipyparallel?

    It would make sense to propose a reference implementation of those, otherwise we will see multiple competing implementation emerge in different projects.

    Besides, it is unlikely that such things would be accepted in core Pandas and numpy as of now...

    (Scipy Trait Types Incubator Proposal)


    8. Would it make sense to have a once version of on_trait_change (now observe)?

    (There seems to be mixed opinions on this. Deferred.)


    9. A common pattern when observing an object is the following:

    foo.observe(do_something) # register to future change notifications.
    do_something()            # act on the current value right away.
    

    maybe we could facilitate this by adding a boolean argument to observe, stating whether to also run the callback right-away or not.

    This would especially be useful when registering observer with the decorator syntax.


    10. One thing that we had in mind in the long-run for widgets is having finer-grained events for containers, such as List and Dict. The ability to create other descriptors than trait types, possibly outside of the traitlets repository could enable experiments in this directions, like an integration of @jdfreder 's eventful dicts and lists.

    One idea that could be in the scope of traitlets though is to add an attribute to the change dictionary indicating the type of notification that is being sent.

    {
        'owner': the HasTraits instance,
        'old': the old trait attribute value,
        'new': the new trait attribute value,
        'name': the name of the changing attribute,
        'type': the type of notification being sent,
    }
    

    The last attribute could be used to define notification types corresponding to operational transforms.

    Then, the @observe decorator would then have a 'type' keyword argument, (defaulting to None), to filter by notification type.

    class Foo(HasTraits):
        bar = Int()
        baz = EventfulList()
    
        @observe('bar')  # Filter to only observe trait changes
        def handler_bar(self, change):
            pass
    
        @observe('baz ', type='element_change')  # Register to element change notifications for `baz`
        def handler_baz(self, change):
            pass
    
        @observe('bar', 'baz', type=All)  # register to all notification types for `bar` and `baz` 
        def handler_all(self, change):
            pass
    

    The only thing to do to enable this possibility would be to add a type item in the dictionary and have the current implementation of observe filter on the notification type.

    (Implemented in #83 - merged)

    opened by SylvainCorlay 66
  • Deprecate on_trait_change and magic change handlers

    Deprecate on_trait_change and magic change handlers

    Deprecation of on_trait_change and the signature of change handlers

    As of now, this PR deprecates on_trait_change and the magic _*foo*_changed handlers, to the benefit of new observe and unobserve method. The signature of the handlers passed to observe is either

    • no argument
    • a single dict argument containing 'name', 'old', 'new' and 'owner', the HasTraits instance emitting the event.

    See the examples below.

    from __future__ import print_function
    from traitlets import *
    
    class Foo(HasTraits):
        bar = Int()
    
        def test_bar(self):
            print('foobar')
    
    foo = Foo()    
    
    def cb(change):
        print(change)
    
    foo.observe(cb)
    foo.bar = 3
    

    Implementation of an observe decorator like in Atom:

    On the other side, atom implements a observe decorator

    class Person(Atom):
        age = Int()
    
        @observe('age')
        def debug_print(self, change):
            print(change['object'].last_name)
    

    The problem is that the registration of the callback requires access self attribute, which is not available when the decorator is called. The way it works in atom is that the @observe('age') decorator replaces the debug_print method with a placeholder object ObserveHandler holding the method to be registered, which is to be picked up and unwrapped by the AtomMeta metaclass when instantiating the instance of (the counterpart to) HasTraits.

    Rather than augmenting the metaclass, I could achieve the same result by making our ObserveHandler inherit from BaseDescriptor, and implement the custom logic in instance_init.

    Example with traitlets:

    class Foo(HasTraits):
        bar = Int()
    
        @observe('bar')
        def test(self):
            print('foobar')
    
    foo = Foo()
    foo.bar = 2
    
    opened by SylvainCorlay 65
  • TraitType init_instance should be able to depend on object initialization arguments

    TraitType init_instance should be able to depend on object initialization arguments

    I am trying to replace my traitlet-like system with the traitlets project. I have a number of "Cluster" objects that have a size member, which is provided to the constructor. They contain numpy array traits that should be sized according to this size:

        class ClusterSizedNDArray(NDArray):
    
            def __init__(self, **metadata):
                super().__init__(cluster_sized=True,
                                 shape=(),
                                 dtype=np.float64,
                                 **metadata)
    
            def shape(self, obj):
                return (obj.size,) + self.metadata['shape']
    
    
        class Cluster(HasTraits):
    
            signals = ClusterSizedNDArray()
    
            def __new__(cls, *args, **kw):
                new_meth = super().__new__
                size = kw.pop('size')
                obj = new_meth(cls, **kw)
                # Initialize size before traits are populated that have that size.
                obj.size = size
                return obj
    
    

    Unfortunately, this doesn't work because obj.size is still not set on the object until after HasTraits.__new__ has been called. What would be a nice way to make this work? Is this something that traitlets can handle or should I implement my own similar system?

    Perhaps I should inherit from another class that just sets the size, so that the mro is Cluster, HasTraits, SizeSettingBaseClass?

    opened by NeilGirdhar 37
  • Roadmap for release

    Roadmap for release

    As suggest by @minrk on the gitter channel, I am opening this to discuss what remains to be done so that we can make a release of traitlets. (There are a few minor PRs open which should probably be merged very soon.)


    It seems that we have checked most of the items listed in #48 for the API changes that we wanted to make. The one remaining thing is the use of a @default decorator instead of the magic function for the default value generation. @rmorshea has a working implementation in #76. I don't think that this issue is blocking to make a release. (Although I don't see a problem getting this in now.)


    Regarding the default value of the type argument in observe, we opted for change in #83 but I am still not sure if it would not be better to default to All. However, we will not be able to change this in a backward compatible fashion after the next release.


    We still depend on ipython_genutils. Is it ok to make a release and keep this?


    Should we make a beta? Should it be 5.0.0 or 4.1.0 ?

    question 
    opened by SylvainCorlay 34
  • Add trait-names autocompletion support

    Add trait-names autocompletion support

    cc @maartenbreddels @SylvainCorlay

    Add a trait-names autocompletion support for HasTraits classes completion_bqplot

    Unfortunately, it does not work with jedi. Which means that this works for ipython=7.1.1 by default, and it will work with other ipython versions only if jedi is not installed.

    I failed to find a way to make it work with jedi.

    5.0-major 
    opened by martinRenou 33
  • Initializing the metadata of a trait

    Initializing the metadata of a trait

    This issue continues discussion of the metadata point from #48. We'd like to separate the metadata from the constructor arguments in a TraitType's constructor: Having the two semantically very different kwarg sets interleaved makes it very difficult to understand the constructor and predict what is going to happen.

    x = Int(allow_none=True, sync=True)           # deprecated
    
    # option A1 - pass metadata in as a separate dict
    x = Int(allow_none=True, metadata={'sync': True})
    x = Int(allow_none=True, metadata=dict(sync=True))
    
    # option A2 - shorter argument name to save typing and line length
    x = Int(allow_none=True, md={'sync': True})
    x = Int(allow_none=True, md=dict(sync=True))
    
    # option B1 - set metadata in a function chained onto the constructor.  .metadata() should return self
    x = Int(allow_none=True).metadata(sync=True)
    
    # option B2 - shorter name
    x = Int(allow_none=True).md(sync=True)
    
    # option B3 - short name from atom, which is a good verb for this
    x = Int(allow_none=True).tag(sync=True)
    

    To be clear, we'd deprecate setting metadata in the constructor immediately, and remove the ability in traitlets 5.0.

    opened by jasongrout 33
  • Envvars

    Envvars

    I believe I Implemented #99 for receiving trait-values from environment-variables with only minimal changes to the codebase. The priority for the source of trait-values is the following (bottom wins):

    1. program defaults (trait.default_value, dynamic_defaults),
    2. config-files,
    3. env-var,
    4. command-line arguments,
    5. values directly assigned.

    Example:

    class App(Application):
        a = Unicode('def').tag(config=True,
                               envvar='MY_ENVVAR')
        b = Unicode().tag(config=True,
                          envvar='MY_ENVVAR')
        aliases = {'a': 'App.a', 'b': 'App.b'}
    
        @default('b')
        def set_a_dyn(self):
            return 'def'
    
    
    cfg = Config()
    cfg.App.a = cfg.App.b = 'cfg'
    
    app = App()
    assert app.a == app.b == 'def'
    
    app = App(config=cfg)
    assert app.a == app.b == 'cfg'
    
    app.parse_command_line(['-a=cmd', '-b=cmd'])
    assert app.a == app.b == 'cmd'
    
    
    os.environ['MY_ENVVAR'] = 'env'
    
    
    app = App()
    assert app.a == app.b == 'env'
    
    app = App(config=cfg)
    assert app.a == app.b == 'env'
    
    app.parse_command_line(['-a=cmd', '-b=cmd'])
    assert app.a == app.b == 'cmd'
    

    And this is the help string:

    >>> print(App.class_get_trait_help(App.a))
    --App.a=<Unicode>
        Env-var: MY_ENVVAR
        Default: 'def'
    

    Implementation:

    The feature is implemented in 3 forward-dependent commits:

    1. trait-layer: The TraitType.metadata['envvar'] stores the name of the environment-variable. That metadata is checked in TraitType.get(), just before defaults. If the env-var exists, its value fetched and cached in _trait_values dict, as a normal value. No specific effort is made for converting string env-vars - use of coercing traits is recommended.

    2. configurable-layer: the Configurable._load_config() does an exception for traits with an existing env-var; in that case, it does not load their values from configs but from the env-var.

    3. application-layer: the Application.parse_command_line() invokes Configurable._load_config(skip_env=True) to bypass the above rule for its command-line config-params. (the skip_env keywords had to be added on update_config() for this to work).

    Rational:

    • Dynamic defaults (#158, #246) wouldn't achieve the desired functionality because configs would overwrite ENV-VAR values.
    • Using a metadata at the trait-layer allows for config and app layers to do informed decisions.
    • It satisfies the @carreau's call for carefullness on the precendence rule and for automatic doc-generation in the presence of env-vars..

    Open issues:

    • Documentation: Where to describe the new capability? Maybe collect all metadata usages in some place?
    • Should we print the envvar-value in the help description, if var exists?
    • Should we add a new Configurable.skip_env trait (not tagged as config of course)? I would vote for *yes. Otherwise, it's impossible to affect this behavior from the constructor, when a config object is given - as it is now, environment always applies, and it overwrites any configs. But adding a new special-purpose trait on Configurable class is too obtrusive for me to decide. [edit:] A cheaper alternative would be to add a special skip_env kwd in configurable's cstor.
    • Is there any other code-path that needs to become env-aware? Is _load_config() & parse_command_line() enough?
    opened by ankostis 26
  • allow default json files in a .d directory

    allow default json files in a .d directory

    This allows to have in addition to a single foobar.json file a foobar.d directory, where all '*.json' files will be read, and used as default values. Would make implementing https://github.com/jupyter/notebook/issues/2824 trivial.

    opened by maartenbreddels 25
  • Notification types

    Notification types

    As per discussion in #48, this enables multiple notification types in traitlets.


    First, the change dictionary passed to registered observers

    • must contain a 'type' key
    • potentially other keys depending on the value for type. For example, when the value for the 'type' key is 'trait_change', we must provide the usual 'owner', 'old', 'new', and 'name'.

    The goal is to enable other types of notifications potentially implementing events for changes of elements in containers like List and Dict. For each type, we may have a different protocol.


    The second thing that is implemented is the ability to filter by notification type when registering an observer. See the following example

    class Foo(HasTraits):
        bar = Int()
        baz = EventfulList()
    
        @observe('bar', type='trait_change')  # Filter to only observe trait changes
        def handler_bar(self, change):
            pass
    
        @observe('baz ', type='element_change')  # Register to element change notifications for baz
        def handler_baz(self, change):
            pass
    
        @observe('bar', 'baz')  # Register to all notification types for `bar` and `baz` 
        def handler_all(self, change):
            pass
    

    Similarly, the observe method also takes a type keyword argument defaulting to None, which corresponds to all types of notifications.

    In terms of implementation, the _trait_notifiers dict is now a dict of dict, the top-level key being the trait name and the second-level being the notification type.


    _notify_trait was refactored into a generic _notify_change that is valid for any type of notification, and the _hold_trait_notifications context manager was updated accordingly.


    Another minor change is that the observe method' s argument name is renamed to names, which is more consistent with what it does.

    opened by SylvainCorlay 24
  • On enabling other descriptors than TraitType

    On enabling other descriptors than TraitType

    The metaclass logic in traitlets is very simple, especially if we remove the deprecated portion of the code. All it does is to decorate the descriptor instances in the dictionary with a name attribute.

    We recently introduced a BaseDescriptor base class to TraitType. The requirement for the specialization to BaseDescriptor is to implement instance_init, which is called in the __new__ method of HasTraits. This was meant to enable using other descriptors than TraitType to benefit from the metaclass magic.

    Within traitlets, we already have another specialization of BaseDescriptor, that isObserveHandler. In widgets, we used it for the work on signaling. @rmorshea is also implementing the registration of custom cross validators with the same mechanism.

    The number of different descriptors that we will introduce is probably going to grow. (Signaling, event-full containers etc), hence I opened this PR, which separates the descriptor mechanics from HasTraits, to acknowledge the fact that other descriptors than TraitType.

    opened by SylvainCorlay 24
  • feat: trait typing

    feat: trait typing

    Took https://github.com/ipython/traitlets/pull/788 and https://github.com/vidartf/traitlets/pull/1 did some fixes for py < 3.10 and squashed it to make rebasing to master easier.

    Closes #788

    enhancement 
    opened by maartenbreddels 9
  • Allow type checkers to infer trait types

    Allow type checkers to infer trait types

    We are currently encoding typing information for traits without integrating with the Python static typing system. This change is for allowing traitlets users to get static typing "for free" by using our trait types.

    Ideally, the typing system would allow for default types, such that TraitType == TraitType[t.Any, t.Any], and TraitType[U] == TraitType[U, U], but for now we have to be verbose for this to work.

    This is currently in a draft state, as some of the typings are still not accurately reflecting all the information we have. Potential improvements:

    • [ ] The Union type should correctly surface its types as the typings union of those of its components
    • [ ] Make the Optional part depend on allow_none (is it possible?).
    • [ ] Improve types of class based traits
    • [ ] Can we make the coercing variants not need to re-inherit TraitType ?
    • [ ] Make Enum and UseEnum types better
    • [ ] etc.

    cc @maartenbreddels

    enhancement 
    opened by vidartf 12
  • `TraitType.make_dynamic_default` is not mentioned in the docs

    `TraitType.make_dynamic_default` is not mentioned in the docs

    Per the title, there is no mention of make_dynamic_default for custom TraitTypes in the docs right now. The current example uses a tuple with two immutable elements, so it's technically safe, but it is at best incomplete (for people who want a mutable default) and at worst misleading (for people who thoughtlessly use a list or other mutable type instead of tuple, or put something mutable inside such a tuple).

    The code itself is very nicely written, so once I decided it ought to be possible to safely have mutable defaults for children of TraitTypes I had no trouble finding the search for make_dynamic_default, but this should be better highlighted in the public-facing documentation.

    opened by liamhuber 0
  • Should we open a discussions tab in this github?

    Should we open a discussions tab in this github?

    Github now supports discussions. I just asked a question which really is not an issue with Traitlets but more a question/discussion about Traitlets.

    In a sense having both discussions and issues makes it harder to search because now you have to search in 2 places for what you are looking for.

    opened by metaperl 0
  • docs do not mention if loading application data from config files is a security risk or not

    docs do not mention if loading application data from config files is a security risk or not

    In the docs on Traitlets configuration via config files the section does not indicate whether arbitrary or potentially malicious code is prevented from executing in these files.

    Are there any security risks involved in using plain Python for traitlets config files?

    opened by metaperl 0
  • Fixup COPYING.md LICENSE.md

    Fixup COPYING.md LICENSE.md

    If possible we should split/rename the COPYING.md file as it's structure make and extra information make some tools (tidelift), not properly detect the license.

    opened by Carreau 0
Releases(v5.8.0)
Owner
IPython
interactive computing in Python
IPython
Flexible Python configuration system. The last one you will ever need.

OmegaConf Description Project Code quality Docs and support OmegaConf is a hierarchical configuration system, with support for merging configurations

Omry Yadan 1.4k Jan 02, 2023
A compact library for Python 3.10x that allows users to configure their SimPads real-time

SimpadLib v1.0.6 What is this? This is a python library programmed by Ashe Muller that allows users to interface directly with their SimPad devices, a

Ashe Muller 2 Jan 08, 2022
A slightly opinionated template for iPython configuration for interactive development

A slightly opinionated template for iPython configuration for interactive development. Auto-reload and no imports for packages and modules in the project.

Seva Zhidkov 24 Feb 16, 2022
filetailor is a peer-based configuration management utility for plain-text files such as dotfiles.

filetailor filetailor is a peer-based configuration management utility for plain-text files (and directories) such as dotfiles. Files are backed up to

5 Dec 23, 2022
Load Django Settings from Environmental Variables with One Magical Line of Code

DjEnv: Django + Environment Load Django Settings Directly from Environmental Variables features modify django configuration without modifying source c

Daniel J. Dufour 28 Oct 01, 2022
Generate config files and qr codes for wireguard vpn

wireguard config generator for python Generate config files and qr codes for wireguard vpn You will need to install qrcode and pillow in python and yo

18 Dec 02, 2022
Config files for my GitHub profile.

Hacked This is a python base script from which you can hack or clone any person's facebook friendlist or followers accounts which have simple password

2 Dec 10, 2021
A helper for organizing Django project settings by relying on well established programming patterns.

django-configurations django-configurations eases Django project configuration by relying on the composability of Python classes. It extends the notio

Jazzband 955 Jan 05, 2023
Inject your config variables into methods, so they are as close to usage as possible

Inject your config variables into methods, so they are as close to usage as possible

GDWR 7 Dec 14, 2022
A Python library to parse PARI/GP configuration and header files

pari-utils A Python library to parse PARI/GP configuration and header files. This is mainly used in the code generation of https://github.com/sagemath

Sage Mathematical Software System 3 Sep 18, 2022
Scooch Configures Object Oriented Class Hierarchies for python

Scooch Scooch Configures Object Oriented Class Hierarchies for python. A good place to start with Scooch is at the documentation found here. Scooch is

Pandora Media, Inc. 6 Dec 20, 2022
Configuration for Python planets

Configuration for Python planets

Python 127 Dec 16, 2022
Strict separation of config from code.

Python Decouple: Strict separation of settings from code Decouple helps you to organize your settings so that you can change parameters without having

Henrique Bastos 2.3k Dec 30, 2022
Python YAML Environment (ymlenv) by Problem Fighter Library

In the name of God, the Most Gracious, the Most Merciful. PF-PY-YMLEnv Documentation Install and update using pip: pip install -U PF-PY-YMLEnv Please

Problem Fighter 2 Jan 20, 2022
Dag-bakery - Dag Bakery enables the capability to define Airflow DAGs via YAML.

DAG Bakery - WIP 🔧 dag-bakery aims to simplify our DAG development by removing all the boilerplate and duplicated code when defining multiple DAG cro

Typeform 2 Jan 08, 2022
A tool to manage configuration files, build scripts etc. across multiple projects.

A tool to manage configuration files, build scripts etc. across multiple projects.

8 Dec 14, 2022
A small example project for efficiently configuring a Python application with YAMLs and the CLI

Hydra Example Project for Python A small example project for efficiently configuring a Python application with YAMLs and the CLI. Why should I care? A

Florian Wilhelm 4 Dec 31, 2022
Configuration Management for Python âš™

dynaconf - Configuration Management for Python. Features Inspired by the 12-factor application guide Settings management (default values, validation,

Bruno Rocha 2.8k Jan 06, 2023
Pyleri is an easy-to-use parser created for SiriDB

Python Left-Right Parser Pyleri is an easy-to-use parser created for SiriDB. We first used lrparsing and wrote jsleri for auto-completion and suggesti

Cesbit 106 Dec 06, 2022
Chinese-specific configuration to improve your favorite DNS server

Dnsmasq-china-list - Chinese-specific configuration to improve your favorite DNS server. Best partner for chnroutes.

Felix Yan 4.6k Jan 03, 2023