Tek bir seçenek koleksiyonu elde etmek için yapılandırma dosyalarını, ortamı ve komut satırı bağımsız değişkenlerini ayrıştırın


110

Python'ın standart kitaplığı için modüllere sahip yapılandırma dosyası ayrıştırma ( ConfigParser ), ortam değişkeni okuma ( os.environ ) ve komut satırı argümanı ayrıştırma ( argparse ). Tüm bunları yapan bir program yazmak istiyorum ve ayrıca:

  • Bir dizi seçenek değerleri vardır :

    • varsayılan seçenek değerleri, geçersiz kılınan
    • yapılandırma dosyası seçenekleri, geçersiz kılınan
    • ortam değişkenleri, geçersiz kılınan
    • komut satırı seçenekleri.
  • Komut satırında örn. İle belirtilen bir veya daha fazla yapılandırma dosyası konumuna izin verir --config-file foo.confve bunu okur (normal yapılandırma dosyası yerine veya ek olarak). Bu yine de yukarıdaki kademeye uymalıdır.

  • Yapılandırma dosyaları ve komut satırı için ayrıştırma davranışını belirlemek için tek bir yerde seçenek tanımlarına izin verir .

  • Ayrıştırılan seçenekleri , programın geri kalanının nereden geldiklerine bakmadan erişmeleri için tek bir seçenek değerleri koleksiyonunda birleştirir .

Görünüşe göre ihtiyacım olan her şey Python standart kütüphanesinde, ancak birlikte sorunsuz çalışmıyorlar.

Python standart kitaplığından minimum sapma ile bunu nasıl başarabilirim?


6
Bu soruyu gerçekten beğendim. Uzun zamandır böyle bir şey yapmayı düşünüyorum ... jterraceBurada, böyle bir şey yapmak için elimi denemeye yetecek kadar beni kenara itmek için bir ödül verdiğim için mutluyum :)
mgilson

4
Harika soru! Bu sorunun uzun zaman önce popüler bir paketle (veya standart kitaplığın kendisi tarafından) çözülmemiş olması şaşırtıcı.
Zearin

Yanıtlar:


33

Argparse modülü, komut satırına benzeyen bir yapılandırma dosyasından memnun olduğunuz sürece bunu çılgınlık yapmaz. (Bunun bir avantaj olduğunu düşünüyorum, çünkü kullanıcıların yalnızca bir sözdizimi öğrenmesi gerekecek.) Dosya_önek_karakterlerinden örneğin, olarak ayarlamak @, bunu şöyle yapar:

my_prog --foo=bar

eşdeğerdir

my_prog @baz.conf

eğer @baz.conf, ise

--foo
bar

Hatta foo.confdeğiştirerek kodunuzun otomatik olarak aramasını bile sağlayabilirsiniz.argv

if os.path.exists('foo.conf'):
    argv = ['@foo.conf'] + argv
args = argparser.parse_args(argv)

Bu konfigürasyon dosyalarının formatı, bir ArgumentParser alt sınıfı oluşturularak ve bir convert_arg_line_to_args yöntemi eklenerek değiştirilebilir .


Birisi daha iyi bir alternatif sunana kadar, bu doğru cevaptır. Argparse kullanıyorum ve bu özelliğe bakmadım bile. Güzel!
Lemur

ama bunun ortam değişkenleri için bir cevabı yok mu?
jterrace

1
@jterrace: Bu SO cevabı işinize yarayabilir: stackoverflow.com/a/10551190/400793
Alex Szatmary

27

GÜNCELLEME: Sonunda bunu pypi'ye koymaya başladım. En son sürümü şu yolla yükleyin:

   pip install configargparser

Tam yardım ve talimatlar burada .

Orijinal gönderi

İşte birlikte hacklediğim küçük bir şey. Yorumlarda iyileştirmeler / hata raporları önermekten çekinmeyin:

import argparse
import ConfigParser
import os

def _identity(x):
    return x

_SENTINEL = object()


class AddConfigFile(argparse.Action):
    def __call__(self,parser,namespace,values,option_string=None):
        # I can never remember if `values` is a list all the time or if it
        # can be a scalar string; this takes care of both.
        if isinstance(values,basestring):
            parser.config_files.append(values)
        else:
            parser.config_files.extend(values)


class ArgumentConfigEnvParser(argparse.ArgumentParser):
    def __init__(self,*args,**kwargs):
        """
        Added 2 new keyword arguments to the ArgumentParser constructor:

           config --> List of filenames to parse for config goodness
           default_section --> name of the default section in the config file
        """
        self.config_files = kwargs.pop('config',[])  #Must be a list
        self.default_section = kwargs.pop('default_section','MAIN')
        self._action_defaults = {}
        argparse.ArgumentParser.__init__(self,*args,**kwargs)


    def add_argument(self,*args,**kwargs):
        """
        Works like `ArgumentParser.add_argument`, except that we've added an action:

           config: add a config file to the parser

        This also adds the ability to specify which section of the config file to pull the 
        data from, via the `section` keyword.  This relies on the (undocumented) fact that
        `ArgumentParser.add_argument` actually returns the `Action` object that it creates.
        We need this to reliably get `dest` (although we could probably write a simple
        function to do this for us).
        """

        if 'action' in kwargs and kwargs['action'] == 'config':
            kwargs['action'] = AddConfigFile
            kwargs['default'] = argparse.SUPPRESS

        # argparse won't know what to do with the section, so 
        # we'll pop it out and add it back in later.
        #
        # We also have to prevent argparse from doing any type conversion,
        # which is done explicitly in parse_known_args.  
        #
        # This way, we can reliably check whether argparse has replaced the default.
        #
        section = kwargs.pop('section', self.default_section)
        type = kwargs.pop('type', _identity)
        default = kwargs.pop('default', _SENTINEL)

        if default is not argparse.SUPPRESS:
            kwargs.update(default=_SENTINEL)
        else:  
            kwargs.update(default=argparse.SUPPRESS)

        action = argparse.ArgumentParser.add_argument(self,*args,**kwargs)
        kwargs.update(section=section, type=type, default=default)
        self._action_defaults[action.dest] = (args,kwargs)
        return action

    def parse_known_args(self,args=None, namespace=None):
        # `parse_args` calls `parse_known_args`, so we should be okay with this...
        ns, argv = argparse.ArgumentParser.parse_known_args(self, args=args, namespace=namespace)
        config_parser = ConfigParser.SafeConfigParser()
        config_files = [os.path.expanduser(os.path.expandvars(x)) for x in self.config_files]
        config_parser.read(config_files)

        for dest,(args,init_dict) in self._action_defaults.items():
            type_converter = init_dict['type']
            default = init_dict['default']
            obj = default

            if getattr(ns,dest,_SENTINEL) is not _SENTINEL: # found on command line
                obj = getattr(ns,dest)
            else: # not found on commandline
                try:  # get from config file
                    obj = config_parser.get(init_dict['section'],dest)
                except (ConfigParser.NoSectionError, ConfigParser.NoOptionError): # Nope, not in config file
                    try: # get from environment
                        obj = os.environ[dest.upper()]
                    except KeyError:
                        pass

            if obj is _SENTINEL:
                setattr(ns,dest,None)
            elif obj is argparse.SUPPRESS:
                pass
            else:
                setattr(ns,dest,type_converter(obj))

        return ns, argv


if __name__ == '__main__':
    fake_config = """
[MAIN]
foo:bar
bar:1
"""
    with open('_config.file','w') as fout:
        fout.write(fake_config)

    parser = ArgumentConfigEnvParser()
    parser.add_argument('--config-file', action='config', help="location of config file")
    parser.add_argument('--foo', type=str, action='store', default="grape", help="don't know what foo does ...")
    parser.add_argument('--bar', type=int, default=7, action='store', help="This is an integer (I hope)")
    parser.add_argument('--baz', type=float, action='store', help="This is an float(I hope)")
    parser.add_argument('--qux', type=int, default='6', action='store', help="this is another int")
    ns = parser.parse_args([])

    parser_defaults = {'foo':"grape",'bar':7,'baz':None,'qux':6}
    config_defaults = {'foo':'bar','bar':1}
    env_defaults = {"baz":3.14159}

    # This should be the defaults we gave the parser
    print ns
    assert ns.__dict__ == parser_defaults

    # This should be the defaults we gave the parser + config defaults
    d = parser_defaults.copy()
    d.update(config_defaults)
    ns = parser.parse_args(['--config-file','_config.file'])
    print ns
    assert ns.__dict__ == d

    os.environ['BAZ'] = "3.14159"

    # This should be the parser defaults + config defaults + env_defaults
    d = parser_defaults.copy()
    d.update(config_defaults)
    d.update(env_defaults)
    ns = parser.parse_args(['--config-file','_config.file'])
    print ns
    assert ns.__dict__ == d

    # This should be the parser defaults + config defaults + env_defaults + commandline
    commandline = {'foo':'3','qux':4} 
    d = parser_defaults.copy()
    d.update(config_defaults)
    d.update(env_defaults)
    d.update(commandline)
    ns = parser.parse_args(['--config-file','_config.file','--foo=3','--qux=4'])
    print ns
    assert ns.__dict__ == d

    os.remove('_config.file')

YAPMAK

Bu uygulama hala tamamlanmamıştır. İşte kısmi bir YAPILACAKLAR listesi:

Belgelenen davranışa uygun

  • (kolay) bir fonksiyon yazın olduğuna dikkat rakamlar destdan argsiçinde add_argumentyerine güvenmek Actionnesne
  • (önemsiz) parse_argsKullanan bir fonksiyon yazın parse_known_args. (örneğin çağırdığından emin parse_argsolmak için cpythonuygulamadan kopyalayın parse_known_args.)

Daha Az Kolay İşler…

Bunların hiçbirini henüz denemedim. Muhtemel değil - ama yine de mümkün! - sadece işe yarayabilir ...


Bunu bir github deposuna atıp herkesin bunu iyileştirebilmesi için bir sorun olur mu?
brent.payne

1
@ brent.payne - github.com/mgilson/configargparser - Bunu gerçek kod olarak yayınlayacaksam, bu gece biraz temizlemek için biraz zaman ayırmaya karar verdim. :-)
mgilson

3
FWIW, sonunda pypi bu koyarak getirmiştim - Sen gerektiğini aracılığıyla yüklemek mümkünpip install configargparser
mgilson

@mgilson - Gönderinizi güncelledim. Bu paket daha fazla kullanımı hak ediyor!
ErichBSchulz

12

Configglue denen bunu tam olarak yapan bir kütüphane var .

configglue, python'un optparse.OptionParser ve ConfigParser.ConfigParser'ı birbirine yapıştıran bir kitaplıktır, böylece aynı seçenekleri bir yapılandırma dosyasına ve bir komut satırı arayüzüne dışa aktarmak istediğinizde kendinizi tekrarlamak zorunda kalmazsınız.

Aynı zamanda ortam değişkenlerini de destekler .

ConfigArgParse adında başka bir kitaplık da var.

Argparse yerine, seçeneklerin yapılandırma dosyaları ve / veya ortam değişkenleri aracılığıyla da ayarlanmasına izin veren bir drop-in yedeği.

PyCon'un Łukasz Langa'nın yapılandırması hakkında konuşması ilginizi çekebilir - Bırakın Yapılandırsınlar!


Ben sordum argparse modülünü desteklemek için herhangi bir plan olup olmadığını.
Piotr Dobrogost

10

Kendi başıma denememiş olsam da, istediğiniz şeylerin çoğunu yaptığını belirten ConfigArgParse kütüphanesi var :

Argparse yerine, seçeneklerin yapılandırma dosyaları ve / veya ortam değişkenleri aracılığıyla da ayarlanmasına izin veren bir drop-in yedeği.


1
Ben denedim, ConfigArgParse çok kullanışlı ve gerçekten de bir drop-in yedek.
maxschlepzig

7

Çakıl her programcı bırakarak standart kütüphane bunu hiç ele almıyor gibi görünüyor configparserve argparseve os.environaksak yollarla tüm buluşmanızı.


5

Python standart kitaplığı bildiğim kadarıyla bunu sağlamıyor. Komut satırını ve yapılandırma dosyalarını kullanmak optparseve ConfigParserayrıştırmak için kod yazarak ve bunların üstüne bir soyutlama katmanı sağlayarak bunu kendim için çözdüm. Bununla birlikte, buna ayrı bir bağımlılık olarak ihtiyacınız olacak ve bu, önceki yorumunuzdan tatsız görünmektedir.

Yazdığım koda bakmak isterseniz, http://liw.fi/cliapp/ adresindedir . Benim "komut satırı uygulama çerçevesi" kitaplığıma entegre edildi çünkü bu, çerçevenin yapması gerekenlerin büyük bir kısmı.


4

Yakın zamanda "optparse" kullanarak buna benzer bir şey denedim.

Bir '--Store' ve bir '--Check' komutuyla bir OptonParser alt sınıfı olarak kurdum.

Aşağıdaki kod hemen hemen sizi kapsamalıdır. Sadece sözlükleri kabul eden / iade eden kendi 'yükleme' ve 'saklama' yöntemlerinizi tanımlamanız gerekir ve çok tuzak edersiniz.


class SmartParse(optparse.OptionParser):
    def __init__(self,defaults,*args,**kwargs):
        self.smartDefaults=defaults
        optparse.OptionParser.__init__(self,*args,**kwargs)
        fileGroup = optparse.OptionGroup(self,'handle stored defaults')
        fileGroup.add_option(
            '-S','--Store',
            dest='Action',
            action='store_const',const='Store',
            help='store command line settings'
        )
        fileGroup.add_option(
            '-C','--Check',
            dest='Action',
            action='store_const',const='Check',
            help ='check stored settings'
        )
        self.add_option_group(fileGroup)
    def parse_args(self,*args,**kwargs):
        (options,arguments) = optparse.OptionParser.parse_args(self,*args,**kwargs)
        action = options.__dict__.pop('Action')
        if action == 'Check':
            assert all(
                value is None 
                for (key,value) in options.__dict__.iteritems() 
            )
            print 'defaults:',self.smartDefaults
            print 'config:',self.load()
            sys.exit()
        elif action == 'Store':
            self.store(options.__dict__)
            sys.exit()
        else:
            config=self.load()
            commandline=dict(
                [key,val] 
                for (key,val) in options.__dict__.iteritems() 
                if val is not None
            )
            result = {}
            result.update(self.defaults)
            result.update(config)
            result.update(commandline)
            return result,arguments
    def load(self):
        return {}
    def store(self,optionDict):
        print 'Storing:',optionDict

ancak Python'un eski sürümleriyle uyumlu kalmak istiyorsanız yine de kullanışlıdır
MarioVilas

3

Tüm bu gereksinimleri karşılamak için, temel işlevsellik için hem [opt | arg] ayrıştırıcı hem de yapılandırıcı ayrıştırıcı kullanan kendi kitaplığınızı yazmanızı tavsiye ederim.

İlk iki ve son gereksinim göz önüne alındığında, şunu istediğinizi söyleyebilirim:

Birinci adım: Yalnızca --config-file seçeneğini arayan bir komut satırı ayrıştırıcı geçişi yapın.

İkinci adım: Yapılandırma dosyasını ayrıştırın.

Üçüncü adım: Yapılandırma dosyası geçişinin çıktısını varsayılan olarak kullanarak ikinci bir komut satırı ayrıştırıcı geçişi ayarlayın.

Üçüncü gereksinim, büyük olasılıkla, ilgilendiğiniz optparse ve configparser'ın tüm işlevlerini ortaya çıkarmak için kendi seçenek tanımlama sisteminizi tasarlamanız ve arada dönüşümler yapmak için biraz tesisat yazmanız gerektiği anlamına gelir.


Bu, umduğumdan çok “Python standart kitaplığından minimum sapma” dan daha uzaktır.
bignose

2

Komut satırı argümanlarını, ortam ayarlarını, ini dosyalarını ve anahtarlık değerlerini de okuyan, birlikte hacklediğim bir modül. Aynı zamanda bir özet olarak da mevcuttur .

"""
Configuration Parser

Configurable parser that will parse config files, environment variables,
keyring, and command-line arguments.



Example test.ini file:

    [defaults]
    gini=10

    [app]
    xini = 50

Example test.arg file:

    --xfarg=30

Example test.py file:

    import os
    import sys

    import config


    def main(argv):
        '''Test.'''
        options = [
            config.Option("xpos",
                          help="positional argument",
                          nargs='?',
                          default="all",
                          env="APP_XPOS"),
            config.Option("--xarg",
                          help="optional argument",
                          default=1,
                          type=int,
                          env="APP_XARG"),
            config.Option("--xenv",
                          help="environment argument",
                          default=1,
                          type=int,
                          env="APP_XENV"),
            config.Option("--xfarg",
                          help="@file argument",
                          default=1,
                          type=int,
                          env="APP_XFARG"),
            config.Option("--xini",
                          help="ini argument",
                          default=1,
                          type=int,
                          ini_section="app",
                          env="APP_XINI"),
            config.Option("--gini",
                          help="global ini argument",
                          default=1,
                          type=int,
                          env="APP_GINI"),
            config.Option("--karg",
                          help="secret keyring arg",
                          default=-1,
                          type=int),
        ]
        ini_file_paths = [
            '/etc/default/app.ini',
            os.path.join(os.path.dirname(os.path.abspath(__file__)),
                         'test.ini')
        ]

        # default usage
        conf = config.Config(prog='app', options=options,
                             ini_paths=ini_file_paths)
        conf.parse()
        print conf

        # advanced usage
        cli_args = conf.parse_cli(argv=argv)
        env = conf.parse_env()
        secrets = conf.parse_keyring(namespace="app")
        ini = conf.parse_ini(ini_file_paths)
        sources = {}
        if ini:
            for key, value in ini.iteritems():
                conf[key] = value
                sources[key] = "ini-file"
        if secrets:
            for key, value in secrets.iteritems():
                conf[key] = value
                sources[key] = "keyring"
        if env:
            for key, value in env.iteritems():
                conf[key] = value
                sources[key] = "environment"
        if cli_args:
            for key, value in cli_args.iteritems():
                conf[key] = value
                sources[key] = "command-line"
        print '\n'.join(['%s:\t%s' % (k, v) for k, v in sources.items()])


    if __name__ == "__main__":
        if config.keyring:
            config.keyring.set_password("app", "karg", "13")
        main(sys.argv)

Example results:

    $APP_XENV=10 python test.py api --xarg=2 @test.arg
    <Config xpos=api, gini=1, xenv=10, xini=50, karg=13, xarg=2, xfarg=30>
    xpos:   command-line
    xenv:   environment
    xini:   ini-file
    karg:   keyring
    xarg:   command-line
    xfarg:  command-line


"""
import argparse
import ConfigParser
import copy
import os
import sys

try:
    import keyring
except ImportError:
    keyring = None


class Option(object):
    """Holds a configuration option and the names and locations for it.

    Instantiate options using the same arguments as you would for an
    add_arguments call in argparse. However, you have two additional kwargs
    available:

        env: the name of the environment variable to use for this option
        ini_section: the ini file section to look this value up from
    """

    def __init__(self, *args, **kwargs):
        self.args = args or []
        self.kwargs = kwargs or {}

    def add_argument(self, parser, **override_kwargs):
        """Add an option to a an argparse parser."""
        kwargs = {}
        if self.kwargs:
            kwargs = copy.copy(self.kwargs)
            try:
                del kwargs['env']
            except KeyError:
                pass
            try:
                del kwargs['ini_section']
            except KeyError:
                pass
        kwargs.update(override_kwargs)
        parser.add_argument(*self.args, **kwargs)

    @property
    def type(self):
        """The type of the option.

        Should be a callable to parse options.
        """
        return self.kwargs.get("type", str)

    @property
    def name(self):
        """The name of the option as determined from the args."""
        for arg in self.args:
            if arg.startswith("--"):
                return arg[2:].replace("-", "_")
            elif arg.startswith("-"):
                continue
            else:
                return arg.replace("-", "_")

    @property
    def default(self):
        """The default for the option."""
        return self.kwargs.get("default")


class Config(object):
    """Parses configuration sources."""

    def __init__(self, options=None, ini_paths=None, **parser_kwargs):
        """Initialize with list of options.

        :param ini_paths: optional paths to ini files to look up values from
        :param parser_kwargs: kwargs used to init argparse parsers.
        """
        self._parser_kwargs = parser_kwargs or {}
        self._ini_paths = ini_paths or []
        self._options = copy.copy(options) or []
        self._values = {option.name: option.default
                        for option in self._options}
        self._parser = argparse.ArgumentParser(**parser_kwargs)
        self.pass_thru_args = []

    @property
    def prog(self):
        """Program name."""
        return self._parser.prog

    def __getitem__(self, key):
        return self._values[key]

    def __setitem__(self, key, value):
        self._values[key] = value

    def __delitem__(self, key):
        del self._values[key]

    def __contains__(self, key):
        return key in self._values

    def __iter__(self):
        return iter(self._values)

    def __len__(self):
        return len(self._values)

    def get(self, key, *args):
        """
        Return the value for key if it exists otherwise the default.
        """
        return self._values.get(key, *args)

    def __getattr__(self, attr):
        if attr in self._values:
            return self._values[attr]
        else:
            raise AttributeError("'config' object has no attribute '%s'"
                                 % attr)

    def build_parser(self, options, **override_kwargs):
        """."""
        kwargs = copy.copy(self._parser_kwargs)
        kwargs.update(override_kwargs)
        if 'fromfile_prefix_chars' not in kwargs:
            kwargs['fromfile_prefix_chars'] = '@'
        parser = argparse.ArgumentParser(**kwargs)
        if options:
            for option in options:
                option.add_argument(parser)
        return parser

    def parse_cli(self, argv=None):
        """Parse command-line arguments into values."""
        if not argv:
            argv = sys.argv
        options = []
        for option in self._options:
            temp = Option(*option.args, **option.kwargs)
            temp.kwargs['default'] = argparse.SUPPRESS
            options.append(temp)
        parser = self.build_parser(options=options)
        parsed, extras = parser.parse_known_args(argv[1:])
        if extras:
            valid, pass_thru = self.parse_passthru_args(argv[1:])
            parsed, extras = parser.parse_known_args(valid)
            if extras:
                raise AttributeError("Unrecognized arguments: %s" %
                                     ' ,'.join(extras))
            self.pass_thru_args = pass_thru + extras
        return vars(parsed)

    def parse_env(self):
        results = {}
        for option in self._options:
            env_var = option.kwargs.get('env')
            if env_var and env_var in os.environ:
                value = os.environ[env_var]
                results[option.name] = option.type(value)
        return results

    def get_defaults(self):
        """Use argparse to determine and return dict of defaults."""
        parser = self.build_parser(options=self._options)
        parsed, _ = parser.parse_known_args([])
        return vars(parsed)

    def parse_ini(self, paths=None):
        """Parse config files and return configuration options.

        Expects array of files that are in ini format.
        :param paths: list of paths to files to parse (uses ConfigParse logic).
                      If not supplied, uses the ini_paths value supplied on
                      initialization.
        """
        results = {}
        config = ConfigParser.SafeConfigParser()
        config.read(paths or self._ini_paths)
        for option in self._options:
            ini_section = option.kwargs.get('ini_section')
            if ini_section:
                try:
                    value = config.get(ini_section, option.name)
                    results[option.name] = option.type(value)
                except ConfigParser.NoSectionError:
                    pass
        return results

    def parse_keyring(self, namespace=None):
        """."""
        results = {}
        if not keyring:
            return results
        if not namespace:
            namespace = self.prog
        for option in self._options:
            secret = keyring.get_password(namespace, option.name)
            if secret:
                results[option.name] = option.type(secret)
        return results

    def parse(self, argv=None):
        """."""
        defaults = self.get_defaults()
        args = self.parse_cli(argv=argv)
        env = self.parse_env()
        secrets = self.parse_keyring()
        ini = self.parse_ini()

        results = defaults
        results.update(ini)
        results.update(secrets)
        results.update(env)
        results.update(args)

        self._values = results
        return self

    @staticmethod
    def parse_passthru_args(argv):
        """Handles arguments to be passed thru to a subprocess using '--'.

        :returns: tuple of two lists; args and pass-thru-args
        """
        if '--' in argv:
            dashdash = argv.index("--")
            if dashdash == 0:
                return argv[1:], []
            elif dashdash > 0:
                return argv[0:dashdash], argv[dashdash + 1:]
        return argv, []

    def __repr__(self):
        return "<Config %s>" % ', '.join([
            '%s=%s' % (k, v) for k, v in self._values.iteritems()])


def comma_separated_strings(value):
    """Handles comma-separated arguments passed in command-line."""
    return map(str, value.split(","))


def comma_separated_pairs(value):
    """Handles comma-separated key/values passed in command-line."""
    pairs = value.split(",")
    results = {}
    for pair in pairs:
        key, pair_value = pair.split('=')
        results[key] = pair_value
    return results


-1

Kütüphane CONFECT inşa ben senin ihtiyaçlarını en karşılamak için tam da budur.

  • Yapılandırma dosyasını, verilen dosya yolları veya modül adı üzerinden birden çok kez yükleyebilir.
  • Yapılandırmaları belirli bir önek ile ortam değişkenlerinden yükler.
  • Bazı tıklama komutlarına komut satırı seçenekleri ekleyebilir

    (üzgünüm, tartışmasız değil, ancak tıklama daha iyi ve çok daha gelişmiş. confectgelecekteki sürümde tartışmayı destekleyebilir).

  • En önemlisi, confectJSON / YMAL / TOML / INI'yi değil Python yapılandırma dosyalarını yükler. IPython profil dosyası veya DJANGO ayarları dosyası gibi, Python yapılandırma dosyası da esnektir ve bakımı daha kolaydır.

Daha fazla bilgi için, lütfen proje havuzundaki README.rst dosyasını kontrol edin . Yalnızca Python3.6 yukarı desteklediğini unutmayın.

Örnekler

Komut satırı seçeneklerini ekleme

import click
from proj_X.core import conf

@click.command()
@conf.click_options
def cli():
    click.echo(f'cache_expire = {conf.api.cache_expire}')

if __name__ == '__main__':
    cli()

Bildirilen tüm özellikler ve varsayılan değerlerle otomatik olarak kapsamlı bir yardım mesajı oluşturur.

$ python -m proj_X.cli --help
Usage: cli.py [OPTIONS]

Options:
  --api-cache_expire INTEGER  [default: 86400]
  --api-cache_prefix TEXT     [default: proj_X_cache]
  --api-url_base_path TEXT    [default: api/v2/]
  --db-db_name TEXT           [default: proj_x]
  --db-username TEXT          [default: proj_x_admin]
  --db-password TEXT          [default: your_password]
  --db-host TEXT              [default: 127.0.0.1]
  --help                      Show this message and exit.

Ortam değişkenlerini yükleme

Ortam değişkenlerini yüklemek için yalnızca bir satır gerekir

conf.load_envvars('proj_X')

> üzgünüm, tartışmasız değil, ancak tıklama daha iyi ve çok daha gelişmiş […] Üçüncü taraf bir kitaplığın yararları ne olursa olsun, bu sorunun cevabı olmadığını gösteriyor.
bignose
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.