alviss


Namealviss JSON
Version 3.3.0 PyPI version JSON
download
home_pageNone
SummaryConfiguration file reader with some nifty bells and whistles added
upload_time2024-05-30 11:43:51
maintainerNone
docs_urlNone
authorNone
requires_pythonNone
licenseMIT License Copyright (c) 2019-2024 CCP Games Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
keywords config configuration json yaml tools ccp utils
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Alviss the all-knowing

Generic Configuration file reader/parser with a bunch of nifty extra 
features, most notably:

- 

JSON & YAML Configuration file reader/parser with built-in fault tolerance and
 ENV variable injecting, structure inheritance, internal referencing and 
secret injection.

## 2.6 Features

* Enabled automatic `fidelius` integration (see: https://gitlab.ccptools.cc/packages/fidelius)


## 2.1 Features

* JSON & YAML config file reading
    * Files can extend base file for easy overriding and customization
    * Files can include multiple other files for better organization and
    structure.
    * Includes/extends can be in a nested structure
* Simple yet powerful internal variable reference parsing
    * Inject values from elsewhere in the config files anywhere
    * Automatic injection of environment variables for values
* Nested fault tolerant fetching of non-existing values
* Quickly nest keys into one with dots
* Easy default value usage
* Password and secret masking
* One line config loading
* ~~Singleton config model~~
* ~~Extendable for multiple singleton configs~~
    * Removed from the basic class in 2.0. Singleton functionality can be
    added by simply extending the `alviss.structs.BaseConfig` on the
    application level and adding the `typeutils.metas.Singleton` as a
    `metaclass`
    * The `alviss.structs.SingletonConfig` sill behaves as the old singleton
    base guy did if people want.


### Singleton reloading/update/set

Reloading (or loading, setting or updating different values) anywhere in code will change them 
globally wherever the same model is referenced.

**Update in one place...**
```python
# Somewhere in the program we decide that reloading the config is in order
from alviss.structs import SingletonConfig

cfg = SingletonConfig()
cfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')

# This will be the same config
cfg2 = SingletonConfig()
assert cfg == cfg2
```

**Updated everywhere...**
```python
# Anywhere the config is needed...
from alviss.structs import SingletonConfig

cfg = SingletonConfig()
assert cfg.foo == 'What is a Foo anyway?'
```

## Updating methods

### Loading/Reloading

Calling `BaseConfig.load(**kwargs)` will clear the entire config data map and 
load up the new values given.

```python
from alviss.structs import BaseConfig

# Initial values...
cfg = BaseConfig()
cfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')

assert cfg.foo == 'Foo Too You!'
assert cfg.bar == 'Salad bar vs. Tequila bar!'

# ...now we reload...
cfg.load(foo='Foo is not a real word!')

# ...so now there is no `bar` in the config
assert cfg.foo == 'What is a Foo anyway?'
assert not cfg.bar
```

Giving the `BaseConfig` constructor `**kwargs` does the same as calling 
`BaseConfig.load(**kwargs)` and will therefor clear and reload the config values
from the supplied keyword arguments.

```python
from alviss.structs import BaseConfig

# Initial values...
cfg = BaseConfig()
cfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')

# This does the same thing
cfg = BaseConfig(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')
```

### Setting values directly

```python
from alviss.structs import BaseConfig

# Initial values...
cfg = BaseConfig()
cfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')

# Updated only the `foo` value, but on a singleton level so it changes everywhere
cfg.foo = 'Nyoo Foo!'
```

### Updating the config

Calling `update(**kwargs)` will update only the given keyword values of the 
config (globally via singleton magic as before) but preserves the existing 
values of the config that did not change (while `load(**kwargs)` wiped the 
config clean first).

```python
from alviss.structs import BaseConfig

# Initial values...
cfg = BaseConfig()
cfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')

# Updated only the given values (leaving `bar` unchanged)
cfg.update(foo='Nyoo Foo!', moo='Shoo!')
```

## Extendable for multiple singleton configs or other magic

You can use the `alviss.structs.SingletonConfig` as a base for implementing
 other 
config classes in order to store different singleton instances of different 
configs.

The singleton mechanism supports inheritance so the new Classes will have their 
own singleton instances separate from each other and from `SingletonConfig`.

```python
from alviss.structs import SingletonConfig


class ClientConfig(SingletonConfig):
    pass


class ServerConfig(SingletonConfig):
    pass


client_cfg = ClientConfig(host='localhost')

server_cfg = ServerConfig(host='127.0.0.1')

assert client_cfg != server_cfg
```

## Quick JSON/YAML Config File Loading

User the `alviss.quickloader` to load a `BaseConfig` from the given JSON or
YAML file.

**The `config.json` file...**
```json
{
    "foo": "Foo Too You!",
    "bar": "Salad bar vs. Tequila bar!"
}
```

**Loading from `config.json`...**
```python
from alviss import quickloader

cfg = quickloader.autoload('config.json')

assert cfg.foo == 'Foo Too You!'
```

## Config file extending/including example

Alviss now supports extending base config files and including files via the
 `__extends__` and `__include__` config keys respectively.

### Extending a base file

Using the `__extends__` key you can embed one or more additional config files
wholesale into another. This works from within the nested key hierarchy so
extended files within nested keys/sections will inject the values there.

Values of keys duplicated in both the current file and the extended files
defined in `__extends__` will retain the value from the current file _(i.e. the
current values override those from the extended base files)_.

The `__extends__` key can take either a single string file name or a list of
files.


**The `base.json` file...**
```json
{
    "foo": "Foo Too You!",
    "bar": {
        "first": "Beer",
        "second": "Wine"
    }
}
```

**The `production.json` file...**
```json
{
    "__extends__": "base.json",
    "bar": {
        "second": "Tequila"
    }
}
```

**Loading `base.json` and overriding with `production.json`...**
```python
from alviss import quickloader

# Assume this comes from an environment variable for example
CONFIG_FILE = 'production.json'

# Loading the base config...
cfg = quickloader.autoload(CONFIG_FILE)

assert cfg.foo == 'Foo Too You!'
assert cfg.bar.first == 'Beer'
assert cfg.bar.second == 'Tequila'
```

### Including additional files

Using the `__include__` key you can embed one or more additional config files
wholesale into another. This works from within the nested key hierarchy so
including files within nested keys/sections will inject the values there.

Values of keys duplicated in both the current file and the included files
defined in `__include__` will retain the value from the last included file 
_(i.e. the included values override those from the current one)_.

The `__include__` key can take either a single string file name or a list of
files.

**The `logging.yaml` file...**
```yaml
level: INFO
file: stuff.log
```

**The `db.yaml` file...**
```yaml
database:
  driver: mysql
  name: mydata
```

**The `extra.yaml` file...**
```yaml
bar: Foo
```

**The `app.yaml` file...**
```yaml
foo: Bar
logging:
  # Default level is DEBUG
  level: DEBUG
  __include__: logging.yaml

bar: NotFoo
__include__: 
- db.yaml
- extra.yaml
```

**Loading `app.yaml`...**
```python
from alviss import quickloader

# Loading the config...
cfg = quickloader.autoload('app.yaml')

assert cfg.foo == 'Bar'
assert cfg.logging.level == 'INFO'
assert cfg.database.driver == 'mysql'
assert cfg.bar == 'Foo'
```

## Quickly reference a nested key with a single key string

You can reference a nested key (e.g. for overriding in an include/extension
) by using dots to separate keys in the path.

**The `config.json` file...**
```json
{
  "database": {
    "settings": {
      "connection": {
        "host": "1.2.3.4",
        "port": 1234      
      }   
    }    
  }
}
```

**The `local.json` file...**
```json
{
  "__extends__": "config.json",
  "database.settings.connection.host": "localhost"
}
```

**Loading `local.json`...**
```python
from alviss import quickloader

# Loading the config...
cfg = quickloader.autoload('local.json')

assert cfg.database.settings.connection.host == 'localhost'
```


## Internal variable referencing

You can reference other config value keys from within any values by using 
`${some.other.key}` from any string value, using dots to navigate key nestings.

**The `config.json` file...**
```json
{
  "basics": {
    "env": "prod"
  },
  "db": {
    "name": "my-data-${basics.env}"    
  }
}
```

**Loading `config.json`...**
```python
from alviss import quickloader

# Loading the config...
cfg = quickloader.autoload('config.json')

assert cfg.db.name == 'my-data-prod'
```

## Automatic injection of environment variables for values

You can automatically inject any environment variables set on the system by
using `${__ENV__:SOME_ENV_VAR}` from within any string value.

**The `config.yaml` file...**
```yaml
user: Foo
password: ${__ENV__:MY_PASS}
```

**Loading from `config.yaml`...**
```python
import os

os.environ.update('MY_PASS', 'SuperSecret!')

from alviss import quickloader

# Loading the config...
cfg = quickloader.autoload('config.yaml')

assert cfg.password == 'SuperSecret!'
```

## Nested fault tolerant fetching of non-existing values

Alviss config models will return an `Empty` and/or `EmptyDict`) from 
`typeutils` if asked for a value that was not in the config file read.

This means that you will never get a `KeyError` or other such exceptions when 
looking up config values, even if search multiple nested levels.

```python
from alviss.structs import *

# Load config...
cfg = BaseConfig(foo={'alpha': 42})

assert cfg.foo.alpha == 42
assert not cfg.foo.beta
assert not cfg.bar
assert not cfg.bar.alpha
assert not cfg.a.b.c.d.e.f
```

To check explicitly if a value has not been set (vs. it's value just being an 
empty string for example) you can check if the value `is typeutils.empty.Empty`

```python
from alviss.structs import *  # Includes a reference to `typeutils.empty.Empty`

# Load config...
cfg = BaseConfig(foo={'alpha': 42})

assert cfg.foo.alpha == 42
assert cfg.foo.beta is Empty
assert cfg.bar is Empty
```

## Easy default value usage 

`Empty` object evaluate as `False` in boolean comparisons so you can ensure 
default values with an `or` bitwise operator.

```python
from alviss.structs import *

# Load config...
cfg = BaseConfig(foo='Foo Too You!')

# Get value or default
my_bar = cfg.bar or 'There was no bar'

assert my_bar == 'There was no bar'
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "alviss",
    "maintainer": null,
    "docs_url": null,
    "requires_python": null,
    "maintainer_email": null,
    "keywords": "config, configuration, json, yaml, tools, ccp, utils",
    "author": null,
    "author_email": "Thordur Matthiasson <thordurm@ccpgames.com>",
    "download_url": "https://files.pythonhosted.org/packages/6c/96/504da7e4b25413b281ec05b5aea7ebf3a9f2e4af7c6d934e939380abb00c/alviss-3.3.0.tar.gz",
    "platform": null,
    "description": "# Alviss the all-knowing\n\nGeneric Configuration file reader/parser with a bunch of nifty extra \nfeatures, most notably:\n\n- \n\nJSON & YAML Configuration file reader/parser with built-in fault tolerance and\n ENV variable injecting, structure inheritance, internal referencing and \nsecret injection.\n\n## 2.6 Features\n\n* Enabled automatic `fidelius` integration (see: https://gitlab.ccptools.cc/packages/fidelius)\n\n\n## 2.1 Features\n\n* JSON & YAML config file reading\n    * Files can extend base file for easy overriding and customization\n    * Files can include multiple other files for better organization and\n    structure.\n    * Includes/extends can be in a nested structure\n* Simple yet powerful internal variable reference parsing\n    * Inject values from elsewhere in the config files anywhere\n    * Automatic injection of environment variables for values\n* Nested fault tolerant fetching of non-existing values\n* Quickly nest keys into one with dots\n* Easy default value usage\n* Password and secret masking\n* One line config loading\n* ~~Singleton config model~~\n* ~~Extendable for multiple singleton configs~~\n    * Removed from the basic class in 2.0. Singleton functionality can be\n    added by simply extending the `alviss.structs.BaseConfig` on the\n    application level and adding the `typeutils.metas.Singleton` as a\n    `metaclass`\n    * The `alviss.structs.SingletonConfig` sill behaves as the old singleton\n    base guy did if people want.\n\n\n### Singleton reloading/update/set\n\nReloading (or loading, setting or updating different values) anywhere in code will change them \nglobally wherever the same model is referenced.\n\n**Update in one place...**\n```python\n# Somewhere in the program we decide that reloading the config is in order\nfrom alviss.structs import SingletonConfig\n\ncfg = SingletonConfig()\ncfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')\n\n# This will be the same config\ncfg2 = SingletonConfig()\nassert cfg == cfg2\n```\n\n**Updated everywhere...**\n```python\n# Anywhere the config is needed...\nfrom alviss.structs import SingletonConfig\n\ncfg = SingletonConfig()\nassert cfg.foo == 'What is a Foo anyway?'\n```\n\n## Updating methods\n\n### Loading/Reloading\n\nCalling `BaseConfig.load(**kwargs)` will clear the entire config data map and \nload up the new values given.\n\n```python\nfrom alviss.structs import BaseConfig\n\n# Initial values...\ncfg = BaseConfig()\ncfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')\n\nassert cfg.foo == 'Foo Too You!'\nassert cfg.bar == 'Salad bar vs. Tequila bar!'\n\n# ...now we reload...\ncfg.load(foo='Foo is not a real word!')\n\n# ...so now there is no `bar` in the config\nassert cfg.foo == 'What is a Foo anyway?'\nassert not cfg.bar\n```\n\nGiving the `BaseConfig` constructor `**kwargs` does the same as calling \n`BaseConfig.load(**kwargs)` and will therefor clear and reload the config values\nfrom the supplied keyword arguments.\n\n```python\nfrom alviss.structs import BaseConfig\n\n# Initial values...\ncfg = BaseConfig()\ncfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')\n\n# This does the same thing\ncfg = BaseConfig(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')\n```\n\n### Setting values directly\n\n```python\nfrom alviss.structs import BaseConfig\n\n# Initial values...\ncfg = BaseConfig()\ncfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')\n\n# Updated only the `foo` value, but on a singleton level so it changes everywhere\ncfg.foo = 'Nyoo Foo!'\n```\n\n### Updating the config\n\nCalling `update(**kwargs)` will update only the given keyword values of the \nconfig (globally via singleton magic as before) but preserves the existing \nvalues of the config that did not change (while `load(**kwargs)` wiped the \nconfig clean first).\n\n```python\nfrom alviss.structs import BaseConfig\n\n# Initial values...\ncfg = BaseConfig()\ncfg.load(foo='Foo Too You!', bar='Salad bar vs. Tequila bar!')\n\n# Updated only the given values (leaving `bar` unchanged)\ncfg.update(foo='Nyoo Foo!', moo='Shoo!')\n```\n\n## Extendable for multiple singleton configs or other magic\n\nYou can use the `alviss.structs.SingletonConfig` as a base for implementing\n other \nconfig classes in order to store different singleton instances of different \nconfigs.\n\nThe singleton mechanism supports inheritance so the new Classes will have their \nown singleton instances separate from each other and from `SingletonConfig`.\n\n```python\nfrom alviss.structs import SingletonConfig\n\n\nclass ClientConfig(SingletonConfig):\n    pass\n\n\nclass ServerConfig(SingletonConfig):\n    pass\n\n\nclient_cfg = ClientConfig(host='localhost')\n\nserver_cfg = ServerConfig(host='127.0.0.1')\n\nassert client_cfg != server_cfg\n```\n\n## Quick JSON/YAML Config File Loading\n\nUser the `alviss.quickloader` to load a `BaseConfig` from the given JSON or\nYAML file.\n\n**The `config.json` file...**\n```json\n{\n    \"foo\": \"Foo Too You!\",\n    \"bar\": \"Salad bar vs. Tequila bar!\"\n}\n```\n\n**Loading from `config.json`...**\n```python\nfrom alviss import quickloader\n\ncfg = quickloader.autoload('config.json')\n\nassert cfg.foo == 'Foo Too You!'\n```\n\n## Config file extending/including example\n\nAlviss now supports extending base config files and including files via the\n `__extends__` and `__include__` config keys respectively.\n\n### Extending a base file\n\nUsing the `__extends__` key you can embed one or more additional config files\nwholesale into another. This works from within the nested key hierarchy so\nextended files within nested keys/sections will inject the values there.\n\nValues of keys duplicated in both the current file and the extended files\ndefined in `__extends__` will retain the value from the current file _(i.e. the\ncurrent values override those from the extended base files)_.\n\nThe `__extends__` key can take either a single string file name or a list of\nfiles.\n\n\n**The `base.json` file...**\n```json\n{\n    \"foo\": \"Foo Too You!\",\n    \"bar\": {\n        \"first\": \"Beer\",\n        \"second\": \"Wine\"\n    }\n}\n```\n\n**The `production.json` file...**\n```json\n{\n    \"__extends__\": \"base.json\",\n    \"bar\": {\n        \"second\": \"Tequila\"\n    }\n}\n```\n\n**Loading `base.json` and overriding with `production.json`...**\n```python\nfrom alviss import quickloader\n\n# Assume this comes from an environment variable for example\nCONFIG_FILE = 'production.json'\n\n# Loading the base config...\ncfg = quickloader.autoload(CONFIG_FILE)\n\nassert cfg.foo == 'Foo Too You!'\nassert cfg.bar.first == 'Beer'\nassert cfg.bar.second == 'Tequila'\n```\n\n### Including additional files\n\nUsing the `__include__` key you can embed one or more additional config files\nwholesale into another. This works from within the nested key hierarchy so\nincluding files within nested keys/sections will inject the values there.\n\nValues of keys duplicated in both the current file and the included files\ndefined in `__include__` will retain the value from the last included file \n_(i.e. the included values override those from the current one)_.\n\nThe `__include__` key can take either a single string file name or a list of\nfiles.\n\n**The `logging.yaml` file...**\n```yaml\nlevel: INFO\nfile: stuff.log\n```\n\n**The `db.yaml` file...**\n```yaml\ndatabase:\n  driver: mysql\n  name: mydata\n```\n\n**The `extra.yaml` file...**\n```yaml\nbar: Foo\n```\n\n**The `app.yaml` file...**\n```yaml\nfoo: Bar\nlogging:\n  # Default level is DEBUG\n  level: DEBUG\n  __include__: logging.yaml\n\nbar: NotFoo\n__include__: \n- db.yaml\n- extra.yaml\n```\n\n**Loading `app.yaml`...**\n```python\nfrom alviss import quickloader\n\n# Loading the config...\ncfg = quickloader.autoload('app.yaml')\n\nassert cfg.foo == 'Bar'\nassert cfg.logging.level == 'INFO'\nassert cfg.database.driver == 'mysql'\nassert cfg.bar == 'Foo'\n```\n\n## Quickly reference a nested key with a single key string\n\nYou can reference a nested key (e.g. for overriding in an include/extension\n) by using dots to separate keys in the path.\n\n**The `config.json` file...**\n```json\n{\n  \"database\": {\n    \"settings\": {\n      \"connection\": {\n        \"host\": \"1.2.3.4\",\n        \"port\": 1234      \n      }   \n    }    \n  }\n}\n```\n\n**The `local.json` file...**\n```json\n{\n  \"__extends__\": \"config.json\",\n  \"database.settings.connection.host\": \"localhost\"\n}\n```\n\n**Loading `local.json`...**\n```python\nfrom alviss import quickloader\n\n# Loading the config...\ncfg = quickloader.autoload('local.json')\n\nassert cfg.database.settings.connection.host == 'localhost'\n```\n\n\n## Internal variable referencing\n\nYou can reference other config value keys from within any values by using \n`${some.other.key}` from any string value, using dots to navigate key nestings.\n\n**The `config.json` file...**\n```json\n{\n  \"basics\": {\n    \"env\": \"prod\"\n  },\n  \"db\": {\n    \"name\": \"my-data-${basics.env}\"    \n  }\n}\n```\n\n**Loading `config.json`...**\n```python\nfrom alviss import quickloader\n\n# Loading the config...\ncfg = quickloader.autoload('config.json')\n\nassert cfg.db.name == 'my-data-prod'\n```\n\n## Automatic injection of environment variables for values\n\nYou can automatically inject any environment variables set on the system by\nusing `${__ENV__:SOME_ENV_VAR}` from within any string value.\n\n**The `config.yaml` file...**\n```yaml\nuser: Foo\npassword: ${__ENV__:MY_PASS}\n```\n\n**Loading from `config.yaml`...**\n```python\nimport os\n\nos.environ.update('MY_PASS', 'SuperSecret!')\n\nfrom alviss import quickloader\n\n# Loading the config...\ncfg = quickloader.autoload('config.yaml')\n\nassert cfg.password == 'SuperSecret!'\n```\n\n## Nested fault tolerant fetching of non-existing values\n\nAlviss config models will return an `Empty` and/or `EmptyDict`) from \n`typeutils` if asked for a value that was not in the config file read.\n\nThis means that you will never get a `KeyError` or other such exceptions when \nlooking up config values, even if search multiple nested levels.\n\n```python\nfrom alviss.structs import *\n\n# Load config...\ncfg = BaseConfig(foo={'alpha': 42})\n\nassert cfg.foo.alpha == 42\nassert not cfg.foo.beta\nassert not cfg.bar\nassert not cfg.bar.alpha\nassert not cfg.a.b.c.d.e.f\n```\n\nTo check explicitly if a value has not been set (vs. it's value just being an \nempty string for example) you can check if the value `is typeutils.empty.Empty`\n\n```python\nfrom alviss.structs import *  # Includes a reference to `typeutils.empty.Empty`\n\n# Load config...\ncfg = BaseConfig(foo={'alpha': 42})\n\nassert cfg.foo.alpha == 42\nassert cfg.foo.beta is Empty\nassert cfg.bar is Empty\n```\n\n## Easy default value usage \n\n`Empty` object evaluate as `False` in boolean comparisons so you can ensure \ndefault values with an `or` bitwise operator.\n\n```python\nfrom alviss.structs import *\n\n# Load config...\ncfg = BaseConfig(foo='Foo Too You!')\n\n# Get value or default\nmy_bar = cfg.bar or 'There was no bar'\n\nassert my_bar == 'There was no bar'\n```\n",
    "bugtrack_url": null,
    "license": "MIT License  Copyright (c) 2019-2024 CCP Games  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.  THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
    "summary": "Configuration file reader with some nifty bells and whistles added",
    "version": "3.3.0",
    "project_urls": {
        "Changelog": "https://github.com/ccpgames/alviss/blob/main/CHANGELOG.md",
        "Documentation": "https://github.com/ccpgames/alviss/blob/main/README.md",
        "Homepage": "https://github.com/ccpgames/alviss",
        "Issues": "https://github.com/ccpgames/alviss/issues",
        "Repository": "https://github.com/ccpgames/alviss.git"
    },
    "split_keywords": [
        "config",
        " configuration",
        " json",
        " yaml",
        " tools",
        " ccp",
        " utils"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6a335c795694615c51771b649b8604f6b38c1d7c4c75c4cb6f924d32e469dc20",
                "md5": "e6f3cc751d7722a55898f782c4665aba",
                "sha256": "9c8f5ef8d6e2ca3425dc229859742239a31168cea2a0f5207994808b7d95cc1f"
            },
            "downloads": -1,
            "filename": "alviss-3.3.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e6f3cc751d7722a55898f782c4665aba",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": null,
            "size": 28214,
            "upload_time": "2024-05-30T11:43:50",
            "upload_time_iso_8601": "2024-05-30T11:43:50.001480Z",
            "url": "https://files.pythonhosted.org/packages/6a/33/5c795694615c51771b649b8604f6b38c1d7c4c75c4cb6f924d32e469dc20/alviss-3.3.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6c96504da7e4b25413b281ec05b5aea7ebf3a9f2e4af7c6d934e939380abb00c",
                "md5": "2d47db2f431b83ee3985b988f0baad8d",
                "sha256": "ddf7181d91bd93347b490d007691f7f64e1a8ed46adfe43a0ca8574b3e234bb4"
            },
            "downloads": -1,
            "filename": "alviss-3.3.0.tar.gz",
            "has_sig": false,
            "md5_digest": "2d47db2f431b83ee3985b988f0baad8d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": null,
            "size": 24715,
            "upload_time": "2024-05-30T11:43:51",
            "upload_time_iso_8601": "2024-05-30T11:43:51.171606Z",
            "url": "https://files.pythonhosted.org/packages/6c/96/504da7e4b25413b281ec05b5aea7ebf3a9f2e4af7c6d934e939380abb00c/alviss-3.3.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-05-30 11:43:51",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "ccpgames",
    "github_project": "alviss",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [],
    "lcname": "alviss"
}
        
Elapsed time: 0.86153s