mirror of
https://git.zavage.net/Zavage-Software/app_skellington.git
synced 2024-12-21 22:29:20 -07:00
Merge branch 'main' of git.zavage.net:Zavage-Software/app_skellington
This commit is contained in:
commit
10e873d2d6
@ -17,10 +17,10 @@ repos:
|
|||||||
args: ["--profile", "black", "--filter-files"]
|
args: ["--profile", "black", "--filter-files"]
|
||||||
|
|
||||||
# Flake8
|
# Flake8
|
||||||
#- repo: https://github.com/pycqa/flake8
|
- repo: https://github.com/pycqa/flake8
|
||||||
# rev: '7.0.0'
|
rev: '7.0.0'
|
||||||
# hooks:
|
hooks:
|
||||||
# - id: flake8
|
- id: flake8
|
||||||
|
|
||||||
# Black
|
# Black
|
||||||
# Using this mirror lets us use mypyc-compiled black, which is about 2x faster
|
# Using this mirror lets us use mypyc-compiled black, which is about 2x faster
|
||||||
@ -29,9 +29,3 @@ repos:
|
|||||||
hooks:
|
hooks:
|
||||||
- id: black
|
- id: black
|
||||||
language_version: python3.8
|
language_version: python3.8
|
||||||
|
|
||||||
# Poetry
|
|
||||||
- repo: https://github.com/python-poetry/poetry
|
|
||||||
rev: 1.8.2
|
|
||||||
hooks:
|
|
||||||
- id: poetry-lock
|
|
||||||
|
35
LICENSE.txt
35
LICENSE.txt
@ -1,25 +1,20 @@
|
|||||||
App Skellington
|
App Skellington
|
||||||
|
|
||||||
|
MIT No Attribution
|
||||||
|
|
||||||
Copyright (c) 2024 Mathew Guest
|
Copyright (c) 2024 Mathew Guest
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
obtaining a copy of this software and associated documentation
|
copy of this software and associated documentation files (the
|
||||||
files (the "Software"), to deal in the Software without
|
"Software"), to deal in the Software without restriction, including
|
||||||
restriction, including without limitation the rights to use,
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||||
copies of the Software, and to permit persons to whom the
|
persons to whom the Software is furnished to do so.
|
||||||
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.
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
160
README.md
160
README.md
@ -1,5 +1,10 @@
|
|||||||
app_skellington
|
---
|
||||||
===============
|
gitea: none
|
||||||
|
include_toc: true
|
||||||
|
---
|
||||||
|
|
||||||
|
**app_skellington**
|
||||||
|
|
||||||
Application framework for Python, features include:
|
Application framework for Python, features include:
|
||||||
- Pain-free multi-level command menu: Expose public class methods as commands available to user.
|
- Pain-free multi-level command menu: Expose public class methods as commands available to user.
|
||||||
- Simple to define services and automatic dependency injection based on name (with custom invocation as an option). \*WIP
|
- Simple to define services and automatic dependency injection based on name (with custom invocation as an option). \*WIP
|
||||||
@ -10,11 +15,31 @@ Application framework for Python, features include:
|
|||||||
Principles:
|
Principles:
|
||||||
- Lend to creating beautiful, easy to read and understand code in the application.
|
- Lend to creating beautiful, easy to read and understand code in the application.
|
||||||
- Minimize coupling of applications to this framework.
|
- Minimize coupling of applications to this framework.
|
||||||
- Compatable with Linux, Windows, and Mac. Try to be compatible as possible otherwise.
|
- Compatible with Linux, Windows, and Mac. Try to be compatible as possible otherwise.
|
||||||
- Try to be compatible with alternate Python runtimes such as PyPy and older python environments. \*WIP
|
- Try to be compatible with alternate Python runtimes such as PyPy and older python environments. \*WIP
|
||||||
|
|
||||||
Application Configuration
|
# Python Package Index (PyPi) - Installation Instruction
|
||||||
-------------------------
|
|
||||||
|
This is the project page for PyPi: The Python Package Index for community third-party libraries
|
||||||
|
|
||||||
|
https://pypi.org/project/app-skellington/
|
||||||
|
|
||||||
|
```
|
||||||
|
pip install app_skellington # install
|
||||||
|
pip uninstall app_skellington # uninstall
|
||||||
|
pip download app_skellington # download .whl wheel files for redistributable install
|
||||||
|
pip install -U app_skellington # upgrade
|
||||||
|
pip list # list install packages in environment
|
||||||
|
pip index version app_skellington # enumerate available distributions in pypi for package
|
||||||
|
```
|
||||||
|
|
||||||
|
# Description
|
||||||
|
|
||||||
|
This is a library. There is nothing to run by itself. It would be helpful to have a sample application that uses
|
||||||
|
it or something, but I don't have that ready at the moment.
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
|
||||||
Site configurations are supported through ConfigObj. There is a config.spec
|
Site configurations are supported through ConfigObj. There is a config.spec
|
||||||
in the src directory which is a validation file; it contains the accepted
|
in the src directory which is a validation file; it contains the accepted
|
||||||
parameter names, types, and limits for configurable options in the
|
parameter names, types, and limits for configurable options in the
|
||||||
@ -32,21 +57,19 @@ parameters are added into the config file.
|
|||||||
|
|
||||||
Linux:
|
Linux:
|
||||||
|
|
||||||
/home/\<user\>/.config/\<app_name\>/config.ini
|
* /home/\<user\>/.config/\<app_name\>/config.ini
|
||||||
|
* /home/\<user\>/.cache/\<app_name\>/log/\<app_name\>.log
|
||||||
/home/\<user\>/.cache/\<app_name\>/log/\<app_name\>.log
|
|
||||||
|
|
||||||
Windows:
|
Windows:
|
||||||
|
|
||||||
C:\\Users\\\<user>\\\<app_name\>\\Local\\\<app_name\>\\config.ini
|
* C:\\Users\\\<user>\\\<app_name\>\\Local\\\<app_name\>\\config.ini
|
||||||
|
* C:\\Users\\\<user>\\\<app_name\>\\Local\\\<app_name\>\\Logs\\\<app_name\>.log
|
||||||
C:\\Users\\\<user>\\\<app_name\>\\Local\\\<app_name\>\\Logs\\\<app_name\>.log
|
|
||||||
|
|
||||||
Application configuration can be overridden ad-hoc through the --config <filename>
|
Application configuration can be overridden ad-hoc through the --config <filename>
|
||||||
argument.
|
argument.
|
||||||
|
|
||||||
Debug - Turn on Logging
|
# Debug - Turn on Logging
|
||||||
-----------------------
|
|
||||||
Set 'APPSKELLINGTON_ENABLE_LOGGING' environment variable to any value which turns
|
Set 'APPSKELLINGTON_ENABLE_LOGGING' environment variable to any value which turns
|
||||||
on AppSkellington-level logging. For example,
|
on AppSkellington-level logging. For example,
|
||||||
|
|
||||||
@ -57,23 +80,32 @@ or
|
|||||||
export APPSKELLINGTON_DEBUG=1
|
export APPSKELLINGTON_DEBUG=1
|
||||||
<executable>
|
<executable>
|
||||||
|
|
||||||
Tests
|
# Tests
|
||||||
-----
|
|
||||||
Tests are a WIP. Recommendation is to run 'pytest' in the 'tests' directory.
|
Tests are a WIP and not fully built out yet. Recommendation is to run 'pytest' in the 'tests' directory.
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
I recommend pyenv to install a reliable, controlled python of preferred version locally.
|
||||||
|
|
||||||
|
```
|
||||||
|
curl https://pyenv.run | bash
|
||||||
|
|
||||||
|
# Add to .bashrc or similar for different shells:
|
||||||
|
tee -a "$HOME"/.profile <<'EOF'
|
||||||
|
|
||||||
|
export PYENV_ROOT="$HOME/.pyenv"
|
||||||
|
[[ -d $PYENV_ROOT/bin ]] && export PATH="$PYENV_ROOT/bin:$PATH"
|
||||||
|
eval "$(pyenv init -)"
|
||||||
|
|
||||||
|
EOF
|
||||||
|
```
|
||||||
|
* reference https://github.com/pyenv/pyenv
|
||||||
|
* Use pyenv to install desired python version, and/or create any virtual environments you desire
|
||||||
|
|
||||||
Development
|
|
||||||
-----------
|
|
||||||
Clone the repo:
|
Clone the repo:
|
||||||
```commandline
|
```commandline
|
||||||
git clone https://git-mirror.zavage.net/zavage-software/app_skellington.git
|
git clone https://git-repos.zavage.net/zavage-software/app_skellington.git
|
||||||
```
|
|
||||||
|
|
||||||
Verify your desired python environment.
|
|
||||||
|
|
||||||
Poetry install to install dependencies and the program in your desired python environment
|
|
||||||
```commandline
|
|
||||||
poetry install
|
|
||||||
# verify no errors
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Install pre-commit hooks:
|
Install pre-commit hooks:
|
||||||
@ -81,16 +113,68 @@ Install pre-commit hooks:
|
|||||||
pre-commit install
|
pre-commit install
|
||||||
```
|
```
|
||||||
|
|
||||||
Begin development.
|
Build:
|
||||||
|
```
|
||||||
|
python -m build
|
||||||
|
```
|
||||||
|
|
||||||
License
|
Install:
|
||||||
-------
|
|
||||||
I'm releasing this software under one of the most permissive
|
|
||||||
licenses, the MIT software license. This applies to this source repository
|
|
||||||
and all files within it. Alternatively, you are permitted you
|
|
||||||
to use any of this under the GPL to the fullest legal extent allowed.
|
|
||||||
|
|
||||||
Notes
|
```
|
||||||
-----
|
pip install .
|
||||||
See official website: https://zavage-software.com
|
```
|
||||||
Please report bugs, improvements, or feedback!
|
|
||||||
|
Formatting and Linters:
|
||||||
|
```
|
||||||
|
black app_skellington
|
||||||
|
isort app_skellington
|
||||||
|
flake8 app_skellington
|
||||||
|
```
|
||||||
|
|
||||||
|
Publish:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Push latest commit, or on commit ready to publish:
|
||||||
|
git push
|
||||||
|
|
||||||
|
# Create a tag with the desired version number and push:
|
||||||
|
git tag -a v0.2.0 -m "0.2.0 provides modern pyproject.toml build with setuptools, versioning, and publishing"
|
||||||
|
git push origin v0.2.0
|
||||||
|
|
||||||
|
# Build the wheel:
|
||||||
|
python -m build
|
||||||
|
|
||||||
|
# Publish to pypi:
|
||||||
|
twine check dist/*
|
||||||
|
twine upload dist/*
|
||||||
|
```
|
||||||
|
* Reference https://packaging.python.org/en/latest/overview/
|
||||||
|
|
||||||
|
|
||||||
|
# Version
|
||||||
|
|
||||||
|
setuptools_scm will infer the version based on the latest tag in your Git history.
|
||||||
|
Ensure you are tagging your commits with meaningful version numbers like v1.0.0, v1.1.0, etc.
|
||||||
|
|
||||||
|
You can view the current version number with the command:
|
||||||
|
|
||||||
|
python -m setuptools_scm
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
See [license](LICENSE.txt)
|
||||||
|
|
||||||
|
MIT no attribution required - https://opensource.org/license/mit-0
|
||||||
|
|
||||||
|
* Allows commercial use.
|
||||||
|
* Allows modifications and closed-source derivatives.
|
||||||
|
* Fully interoperable with nearly all other open-source licenses, including GPL (when combined properly).
|
||||||
|
|
||||||
|
# See Also
|
||||||
|
|
||||||
|
* Project page: https://zavage-software.com/portfolio/app_skellington
|
||||||
|
* Please report bugs, improvements, or feedback!
|
||||||
|
* Contact: mat@zavage.net
|
||||||
|
|
||||||
|
* Packing and distribution conforms to PEP 621 https://peps.python.org/pep-0621/
|
||||||
|
* Reference https://packaging.python.org/en/latest/guides/distributing-packages-using-setuptools/
|
||||||
|
@ -1,7 +1,19 @@
|
|||||||
import logging
|
# flake8: noqa
|
||||||
import sys
|
|
||||||
|
|
||||||
from .app_container import *
|
from .app_container import (
|
||||||
from .cfg import *
|
DEFAULT_APP_AUTHOR,
|
||||||
from .cli import *
|
DEFAULT_APP_NAME,
|
||||||
from .log import *
|
ApplicationContainer,
|
||||||
|
ApplicationContext,
|
||||||
|
NoCommandSpecified,
|
||||||
|
ServiceNotFound,
|
||||||
|
)
|
||||||
|
from .cfg import Config, EnvironmentVariables
|
||||||
|
from .cli import (
|
||||||
|
EXPLICIT_FAIL_ON_UNKNOWN_ARGS,
|
||||||
|
CommandEntry,
|
||||||
|
CommandTree,
|
||||||
|
HelpGenerator,
|
||||||
|
SubMenu,
|
||||||
|
)
|
||||||
|
from .log import LoggingLayer
|
||||||
|
@ -39,7 +39,9 @@ if os.environ.get("APPSKELLINGTON_DEBUG", None):
|
|||||||
handler = logging.StreamHandler()
|
handler = logging.StreamHandler()
|
||||||
handler.setFormatter(fmt)
|
handler.setFormatter(fmt)
|
||||||
_bootstrap_logger.addHandler(handler)
|
_bootstrap_logger.addHandler(handler)
|
||||||
_bootstrap_logger.debug("log - APPSKELLINGTON_DEBUG set in environment: Enabling verbose logging.")
|
_bootstrap_logger.debug(
|
||||||
|
"log - APPSKELLINGTON_DEBUG set in environment: Enabling verbose logging."
|
||||||
|
)
|
||||||
|
|
||||||
# Logging is by default off, excepting CRITICAL
|
# Logging is by default off, excepting CRITICAL
|
||||||
else:
|
else:
|
||||||
|
@ -4,8 +4,6 @@ import inspect
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from . import _util
|
|
||||||
|
|
||||||
|
|
||||||
def eprint(*args, **kwargs):
|
def eprint(*args, **kwargs):
|
||||||
"""
|
"""
|
||||||
@ -30,9 +28,9 @@ def does_file_exist(filepath):
|
|||||||
instant in execution.
|
instant in execution.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
fp = open(filepath, "r")
|
open(filepath, "r")
|
||||||
return True
|
return True
|
||||||
except FileNotFoundError as ex:
|
except FileNotFoundError:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
@ -88,7 +86,7 @@ def get_asset(module, filepath):
|
|||||||
root = os.path.realpath(root)
|
root = os.path.realpath(root)
|
||||||
|
|
||||||
root = os.path.dirname(os.path.abspath(root))
|
root = os.path.dirname(os.path.abspath(root))
|
||||||
except Exception as ex:
|
except Exception:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
path = os.path.join(root, filepath)
|
path = os.path.join(root, filepath)
|
||||||
|
17
app_skellington/_version.py
Normal file
17
app_skellington/_version.py
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# file generated by setuptools_scm
|
||||||
|
# don't change, don't track in version control
|
||||||
|
TYPE_CHECKING = False
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from typing import Tuple, Union
|
||||||
|
|
||||||
|
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
||||||
|
else:
|
||||||
|
VERSION_TUPLE = object
|
||||||
|
|
||||||
|
version: str
|
||||||
|
__version__: str
|
||||||
|
__version_tuple__: VERSION_TUPLE
|
||||||
|
version_tuple: VERSION_TUPLE
|
||||||
|
|
||||||
|
__version__ = version = "0.2.2"
|
||||||
|
__version_tuple__ = version_tuple = (0, 2, 2)
|
@ -1,18 +1,10 @@
|
|||||||
import collections
|
|
||||||
import functools
|
import functools
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
|
|
||||||
import appdirs
|
import appdirs
|
||||||
|
|
||||||
from . import (
|
from . import _util, cfg, cli, log
|
||||||
_util,
|
|
||||||
cfg,
|
|
||||||
cli,
|
|
||||||
log,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Application scaffolding:
|
# Application scaffolding:
|
||||||
from ._bootstrap import _bootstrap_logger
|
from ._bootstrap import _bootstrap_logger
|
||||||
@ -47,7 +39,9 @@ class ApplicationContainer:
|
|||||||
directories.
|
directories.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, configspec_filepath=None, configini_filepath=None, *args, **kwargs):
|
def __init__(
|
||||||
|
self, configspec_filepath=None, configini_filepath=None, *args, **kwargs
|
||||||
|
):
|
||||||
self.appname = kwargs.get("appname") or DEFAULT_APP_NAME
|
self.appname = kwargs.get("appname") or DEFAULT_APP_NAME
|
||||||
self.appauthor = kwargs.get("appauthor") or DEFAULT_APP_AUTHOR
|
self.appauthor = kwargs.get("appauthor") or DEFAULT_APP_AUTHOR
|
||||||
|
|
||||||
@ -89,7 +83,7 @@ class ApplicationContainer:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
del self._dependencies[service_name]
|
del self._dependencies[service_name]
|
||||||
except KeyError as ex:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __getitem__(self, service_name):
|
def __getitem__(self, service_name):
|
||||||
@ -100,9 +94,11 @@ class ApplicationContainer:
|
|||||||
app['datalayer'] => returns the made-up "datalayer" service.
|
app['datalayer'] => returns the made-up "datalayer" service.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
service_factory = self._dependencies[service_name] # Retrieve factory function
|
service_factory = self._dependencies[
|
||||||
|
service_name
|
||||||
|
] # Retrieve factory function
|
||||||
return service_factory() # Call factory() to return instance of service
|
return service_factory() # Call factory() to return instance of service
|
||||||
except KeyError as ex:
|
except KeyError:
|
||||||
msg = "failed to inject service: {}".format(service_name)
|
msg = "failed to inject service: {}".format(service_name)
|
||||||
_bootstrap_logger.critical(msg)
|
_bootstrap_logger.critical(msg)
|
||||||
raise ServiceNotFound
|
raise ServiceNotFound
|
||||||
@ -160,7 +156,9 @@ class ApplicationContainer:
|
|||||||
"""
|
"""
|
||||||
sig = inspect.signature(constructor.__init__)
|
sig = inspect.signature(constructor.__init__)
|
||||||
params = sig.parameters
|
params = sig.parameters
|
||||||
params = [params[paramname].name for paramname in params] # Convert Param() type => str
|
params = [
|
||||||
|
params[paramname].name for paramname in params
|
||||||
|
] # Convert Param() type => str
|
||||||
cls_dependencies = params[1:] # Skip 'self' parameter on class methods.
|
cls_dependencies = params[1:] # Skip 'self' parameter on class methods.
|
||||||
|
|
||||||
return functools.partial(self._construct_model, constructor, *cls_dependencies)
|
return functools.partial(self._construct_model, constructor, *cls_dependencies)
|
||||||
@ -179,12 +177,9 @@ class ApplicationContainer:
|
|||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
self.cli.run_command()
|
self.cli.run_command()
|
||||||
except NoCommandSpecified as ex:
|
except NoCommandSpecified:
|
||||||
print("Failure: No command specified.")
|
print("Failure: No command specified.")
|
||||||
|
|
||||||
def interactive_shell(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def invoke_from_cli(self):
|
def invoke_from_cli(self):
|
||||||
self.invoke_command()
|
self.invoke_command()
|
||||||
|
|
||||||
|
@ -4,15 +4,10 @@
|
|||||||
# ConfigObj module and it's recommended to use config.spec files to define
|
# ConfigObj module and it's recommended to use config.spec files to define
|
||||||
# your available configuration of the relevant application.
|
# your available configuration of the relevant application.
|
||||||
|
|
||||||
import argparse
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import appdirs
|
|
||||||
import configobj
|
import configobj
|
||||||
import validate
|
import validate
|
||||||
|
|
||||||
from . import _util
|
|
||||||
from ._bootstrap import _bootstrap_logger
|
from ._bootstrap import _bootstrap_logger
|
||||||
|
|
||||||
|
|
||||||
@ -31,7 +26,9 @@ class Config:
|
|||||||
"allow_options_beyond_spec": True,
|
"allow_options_beyond_spec": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, configspec_filepath=None, configini_filepath=None, capabilities=None):
|
def __init__(
|
||||||
|
self, configspec_filepath=None, configini_filepath=None, capabilities=None
|
||||||
|
):
|
||||||
self._config_obj = None # must be type configobj.ConfigObj()
|
self._config_obj = None # must be type configobj.ConfigObj()
|
||||||
self._configini_data = None
|
self._configini_data = None
|
||||||
self._configini_filepath = None
|
self._configini_filepath = None
|
||||||
@ -93,11 +90,15 @@ class Config:
|
|||||||
self._configspec_filepath = filepath
|
self._configspec_filepath = filepath
|
||||||
self._configspec_data = data
|
self._configspec_data = data
|
||||||
self._has_changed_internally = True
|
self._has_changed_internally = True
|
||||||
_bootstrap_logger.debug("cfg - Set configspec and read contents: %s", filepath)
|
_bootstrap_logger.debug(
|
||||||
|
"cfg - Set configspec and read contents: %s", filepath
|
||||||
|
)
|
||||||
self.load_config()
|
self.load_config()
|
||||||
return
|
return
|
||||||
except OSError as ex:
|
except OSError:
|
||||||
_bootstrap_logger.critical("cfg - Failed to find config.spec: file not found (%s)", filepath)
|
_bootstrap_logger.critical(
|
||||||
|
"cfg - Failed to find config.spec: file not found (%s)", filepath
|
||||||
|
)
|
||||||
raise OSError("Failed to read provided config.spec file")
|
raise OSError("Failed to read provided config.spec file")
|
||||||
|
|
||||||
self.load_config()
|
self.load_config()
|
||||||
@ -106,7 +107,7 @@ class Config:
|
|||||||
try:
|
try:
|
||||||
has_item = key in self._config_obj
|
has_item = key in self._config_obj
|
||||||
return has_item
|
return has_item
|
||||||
except KeyError as ex:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __delitem__(self, key):
|
def __delitem__(self, key):
|
||||||
@ -116,7 +117,7 @@ class Config:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
del self[key]
|
del self[key]
|
||||||
except KeyError as ex:
|
except KeyError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
@ -130,7 +131,7 @@ class Config:
|
|||||||
else:
|
else:
|
||||||
# return self._config_obj[key].dict()
|
# return self._config_obj[key].dict()
|
||||||
return self._config_obj[key]
|
return self._config_obj[key]
|
||||||
except KeyError as ex:
|
except KeyError:
|
||||||
raise
|
raise
|
||||||
|
|
||||||
def __setitem__(self, key, value):
|
def __setitem__(self, key, value):
|
||||||
@ -150,7 +151,7 @@ class Config:
|
|||||||
try:
|
try:
|
||||||
v = self.__getitem__(key)
|
v = self.__getitem__(key)
|
||||||
return v
|
return v
|
||||||
except KeyError as ex:
|
except KeyError:
|
||||||
return default
|
return default
|
||||||
|
|
||||||
def load_config(self, configspec_filepath=None, configini_filepath=None):
|
def load_config(self, configspec_filepath=None, configini_filepath=None):
|
||||||
@ -187,20 +188,23 @@ class Config:
|
|||||||
# raise_errors
|
# raise_errors
|
||||||
)
|
)
|
||||||
_bootstrap_logger.debug(
|
_bootstrap_logger.debug(
|
||||||
"cfg - Parsed configuration. config.spec = %s, config.ini = %s", config_spec, config_ini
|
"cfg - Parsed configuration. config.spec = %s, config.ini = %s",
|
||||||
|
config_spec,
|
||||||
|
config_ini,
|
||||||
)
|
)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
except configobj.ParseError as ex:
|
except configobj.ParseError:
|
||||||
msg = "cfg - Failed to load config: error in config.spec configuration: {}".format(config_filepath)
|
msg = f"cfg - Failed to load config: error in config.spec configuration: {self.configspec_filepath}"
|
||||||
_bootstrap_logger.error(msg)
|
_bootstrap_logger.error(msg)
|
||||||
return False
|
return False
|
||||||
except OSError as ex:
|
except OSError:
|
||||||
msg = "cfg - Failed to load config: config.spec file not found."
|
msg = "cfg - Failed to load config: config.spec file not found."
|
||||||
_bootstrap_logger.error(msg)
|
_bootstrap_logger.error(msg)
|
||||||
return False
|
return False
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print(ex)
|
_bootstrap_logger.error(ex)
|
||||||
|
return False
|
||||||
|
|
||||||
def _validate_config_against_spec(self):
|
def _validate_config_against_spec(self):
|
||||||
config_spec = self.configspec_filepath
|
config_spec = self.configspec_filepath
|
||||||
@ -217,7 +221,9 @@ class Config:
|
|||||||
self._config_obj, configobj.ConfigObj
|
self._config_obj, configobj.ConfigObj
|
||||||
), "expecting configobj.ConfigObj, received %s" % type(self._config_obj)
|
), "expecting configobj.ConfigObj, received %s" % type(self._config_obj)
|
||||||
# NOTE(MG) copy arg below instructs configobj to use defaults from spec file
|
# NOTE(MG) copy arg below instructs configobj to use defaults from spec file
|
||||||
test_results = self._config_obj.validate(val, copy=True, preserve_errors=True)
|
test_results = self._config_obj.validate(
|
||||||
|
val, copy=True, preserve_errors=True
|
||||||
|
)
|
||||||
if test_results is True:
|
if test_results is True:
|
||||||
_bootstrap_logger.info(
|
_bootstrap_logger.info(
|
||||||
"cfg- Successfully validated configuration against spec. input = %s, validation spec = %s",
|
"cfg- Successfully validated configuration against spec. input = %s, validation spec = %s",
|
||||||
@ -227,19 +233,27 @@ class Config:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
elif test_results is False:
|
elif test_results is False:
|
||||||
_bootstrap_logger.debug("cfg - Potentially discovered invalid config.spec")
|
_bootstrap_logger.debug(
|
||||||
|
"cfg - Potentially discovered invalid config.spec"
|
||||||
|
)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self._validate_parse_errors(test_results)
|
self._validate_parse_errors(test_results)
|
||||||
return False
|
return False
|
||||||
except ValueError as ex:
|
except ValueError:
|
||||||
_bootstrap_logger.error("cfg - Failed while validating config against spec. ")
|
_bootstrap_logger.error(
|
||||||
|
"cfg - Failed while validating config against spec. "
|
||||||
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _validate_parse_errors(self, test_results):
|
def _validate_parse_errors(self, test_results):
|
||||||
_bootstrap_logger.critical("cfg - Config file failed validation.")
|
_bootstrap_logger.critical("cfg - Config file failed validation.")
|
||||||
for section_list, key, rslt in configobj.flatten_errors(self._config_obj, test_results):
|
for section_list, key, rslt in configobj.flatten_errors(
|
||||||
_bootstrap_logger.critical("cfg - Config error info: %s %s %s", section_list, key, rslt)
|
self._config_obj, test_results
|
||||||
|
):
|
||||||
|
_bootstrap_logger.critical(
|
||||||
|
"cfg - Config error info: %s %s %s", section_list, key, rslt
|
||||||
|
)
|
||||||
if key is not None:
|
if key is not None:
|
||||||
_bootstrap_logger.critical(
|
_bootstrap_logger.critical(
|
||||||
"cfg - Config failed validation: [%s].%s appears invalid. msg = %s",
|
"cfg - Config failed validation: [%s].%s appears invalid. msg = %s",
|
||||||
|
@ -1,12 +1,9 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import inspect
|
import inspect
|
||||||
import logging
|
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
import app_skellington
|
from . import NoCommandSpecified, app_container
|
||||||
|
|
||||||
from . import app_container
|
|
||||||
from ._bootstrap import _bootstrap_logger
|
from ._bootstrap import _bootstrap_logger
|
||||||
|
|
||||||
# If explicit fail is enabled, any command with at least one unknown
|
# If explicit fail is enabled, any command with at least one unknown
|
||||||
@ -44,12 +41,12 @@ class CommandTree:
|
|||||||
|
|
||||||
./scriptname --option="value" [submenu] [command]
|
./scriptname --option="value" [submenu] [command]
|
||||||
|
|
||||||
is different than
|
is different from
|
||||||
|
|
||||||
./scriptname [submenu] [command] --option="value"
|
./scriptname [submenu] [command] --option="value"
|
||||||
|
|
||||||
in that option is being applied to the application in the first example and
|
in that option is being applied to the application in the first example and
|
||||||
applied to the refresh_datasets command (under the nhsn command group) in
|
applied to the command (under the submenu command group) in
|
||||||
the second. In the same way the -h, --help options print different docs
|
the second. In the same way the -h, --help options print different docs
|
||||||
depending on where the help option was passed.
|
depending on where the help option was passed.
|
||||||
"""
|
"""
|
||||||
@ -69,13 +66,15 @@ class CommandTree:
|
|||||||
self._single_command = None
|
self._single_command = None
|
||||||
|
|
||||||
def print_tree(self):
|
def print_tree(self):
|
||||||
raise NotImplemented
|
raise NotImplementedError
|
||||||
|
|
||||||
def add_argument(self, *args, **kwargs):
|
def add_argument(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Adds an argument to the root parser.
|
Adds an argument to the root parser.
|
||||||
"""
|
"""
|
||||||
_bootstrap_logger.info("adding argument to root parser: %s and %s", args, kwargs)
|
_bootstrap_logger.info(
|
||||||
|
"adding argument to root parser: %s and %s", args, kwargs
|
||||||
|
)
|
||||||
self.root_parser.add_argument(*args, **kwargs)
|
self.root_parser.add_argument(*args, **kwargs)
|
||||||
|
|
||||||
def init_submenu(self, param_name, is_required=False):
|
def init_submenu(self, param_name, is_required=False):
|
||||||
@ -83,15 +82,7 @@ class CommandTree:
|
|||||||
Creates a root-level submenu with no entries. SubMenu node is
|
Creates a root-level submenu with no entries. SubMenu node is
|
||||||
returned which can have submenus and commands attached to it.
|
returned which can have submenus and commands attached to it.
|
||||||
"""
|
"""
|
||||||
# NOTE(MG) Fix for Python>=3.7,
|
|
||||||
# argparse.ArgumentParser added 'required' argument.
|
|
||||||
# Must also be written into SubMenu.create_submenu.
|
|
||||||
func_args = {"dest": param_name, "metavar": param_name, "required": is_required}
|
func_args = {"dest": param_name, "metavar": param_name, "required": is_required}
|
||||||
if sys.version_info.major == 3 and sys.version_info.minor < 7:
|
|
||||||
if is_required:
|
|
||||||
_bootstrap_logger.warn("Unable to enforce required submenu: Requires >= Python 3.7")
|
|
||||||
del func_args["required"]
|
|
||||||
# END fix for Python<3.7
|
|
||||||
|
|
||||||
# Creates an argument as a slot in the underlying argparse.
|
# Creates an argument as a slot in the underlying argparse.
|
||||||
subparsers = self.root_parser.add_subparsers(**func_args)
|
subparsers = self.root_parser.add_subparsers(**func_args)
|
||||||
@ -100,13 +91,17 @@ class CommandTree:
|
|||||||
submenu.submenu_path = ""
|
submenu.submenu_path = ""
|
||||||
submenu.var_name = param_name
|
submenu.var_name = param_name
|
||||||
|
|
||||||
_bootstrap_logger.info("Initialized root-level submenu: Parameter = '%s'", param_name)
|
_bootstrap_logger.info(
|
||||||
|
"Initialized root-level submenu: Parameter = '%s'", param_name
|
||||||
|
)
|
||||||
self.entries[param_name] = submenu
|
self.entries[param_name] = submenu
|
||||||
self.submenu_param = param_name
|
self.submenu_param = param_name
|
||||||
|
|
||||||
return submenu
|
return submenu
|
||||||
|
|
||||||
def register_command(self, func, cmd_name=None, func_signature=None, docstring=None):
|
def register_command(
|
||||||
|
self, func, cmd_name=None, func_signature=None, docstring=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
When no submenu functionality is desired, this links a single
|
When no submenu functionality is desired, this links a single
|
||||||
command into underlying argparse options.
|
command into underlying argparse options.
|
||||||
@ -136,13 +131,13 @@ class CommandTree:
|
|||||||
|
|
||||||
# help is displayed next to the command in the submenu enumeration or
|
# help is displayed next to the command in the submenu enumeration or
|
||||||
# list of commands:
|
# list of commands:
|
||||||
help_text = HelpGenerator.generate_help_from_sig(docstring)
|
HelpGenerator.generate_help_from_sig(docstring)
|
||||||
# description is displayed when querying help for the specific command:
|
# description is displayed when querying help for the specific command:
|
||||||
description_text = HelpGenerator.generate_description_from_sig(docstring)
|
HelpGenerator.generate_description_from_sig(docstring)
|
||||||
# end copy-paste from SubMenu.register_command
|
# end copy-paste from SubMenu.register_command
|
||||||
|
|
||||||
# begin copy-paste then editted from SubMenu.register_command
|
# begin copy-paste then edited from SubMenu.register_command
|
||||||
# For each paramter in the function create an argparse argument in
|
# For each parameter in the function create an argparse argument in
|
||||||
# the child ArgumentParser created for this menu entry:
|
# the child ArgumentParser created for this menu entry:
|
||||||
for key in params:
|
for key in params:
|
||||||
if key == "self":
|
if key == "self":
|
||||||
@ -154,7 +149,9 @@ class CommandTree:
|
|||||||
helptext = "default provided"
|
helptext = "default provided"
|
||||||
else:
|
else:
|
||||||
helptext = "default = '{}'".format(param.default)
|
helptext = "default = '{}'".format(param.default)
|
||||||
self.root_parser.add_argument(key, help=helptext, nargs="?", default=param.default)
|
self.root_parser.add_argument(
|
||||||
|
key, help=helptext, nargs="?", default=param.default
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
helptext = "required"
|
helptext = "required"
|
||||||
self.root_parser.add_argument(key, help=helptext)
|
self.root_parser.add_argument(key, help=helptext)
|
||||||
@ -169,7 +166,7 @@ class CommandTree:
|
|||||||
|
|
||||||
registered_name = cmd_name
|
registered_name = cmd_name
|
||||||
_bootstrap_logger.info("registered command: %s", registered_name)
|
_bootstrap_logger.info("registered command: %s", registered_name)
|
||||||
# end copy-paste then editted from SubMenu.register_command
|
# end copy-paste then edited from SubMenu.register_command
|
||||||
|
|
||||||
self._cmd_tree_is_single_command = True
|
self._cmd_tree_is_single_command = True
|
||||||
self._single_command = cmd
|
self._single_command = cmd
|
||||||
@ -200,10 +197,16 @@ class CommandTree:
|
|||||||
return pargs, unk, True
|
return pargs, unk, True
|
||||||
|
|
||||||
# Note: SystemExit is raised when '-h' argument is supplied.
|
# Note: SystemExit is raised when '-h' argument is supplied.
|
||||||
except SystemExit as ex:
|
except SystemExit:
|
||||||
return None, None, False
|
return None, None, False
|
||||||
|
|
||||||
def run_command(self, args=None):
|
def run_command(self, args=None):
|
||||||
|
"""
|
||||||
|
Args:
|
||||||
|
args (list[str]): Direct from STDIN
|
||||||
|
Raises:
|
||||||
|
NoCommandSpecified for invalid command.
|
||||||
|
"""
|
||||||
args, unk, success = self.parse(args)
|
args, unk, success = self.parse(args)
|
||||||
if not success:
|
if not success:
|
||||||
_bootstrap_logger.info("cli - SystemExit: Perhaps user invoked --help")
|
_bootstrap_logger.info("cli - SystemExit: Perhaps user invoked --help")
|
||||||
@ -219,7 +222,7 @@ class CommandTree:
|
|||||||
cmd = self._lookup_command(args)
|
cmd = self._lookup_command(args)
|
||||||
if cmd is None:
|
if cmd is None:
|
||||||
_bootstrap_logger.critical("cli - Failed to find command.")
|
_bootstrap_logger.critical("cli - Failed to find command.")
|
||||||
return False
|
raise NoCommandSpecified
|
||||||
|
|
||||||
return self._invoke_command(cmd, args)
|
return self._invoke_command(cmd, args)
|
||||||
|
|
||||||
@ -230,16 +233,22 @@ class CommandTree:
|
|||||||
# the CommandTree with no SubMenu (submenu will be disabled
|
# the CommandTree with no SubMenu (submenu will be disabled
|
||||||
# in this case):
|
# in this case):
|
||||||
if self._cmd_tree_is_single_command:
|
if self._cmd_tree_is_single_command:
|
||||||
assert self._cmd_tree_is_single_command is True, "corrupt data structure in CommandMenu"
|
assert (
|
||||||
|
self._cmd_tree_is_single_command is True
|
||||||
|
), "corrupt data structure in CommandMenu"
|
||||||
assert self._entries is None, "corrupt data structure in CommandMenu"
|
assert self._entries is None, "corrupt data structure in CommandMenu"
|
||||||
assert isinstance(self._single_command, CommandEntry), "corrupt data structure in CommandMenu"
|
assert isinstance(
|
||||||
|
self._single_command, CommandEntry
|
||||||
|
), "corrupt data structure in CommandMenu"
|
||||||
return self._single_command
|
return self._single_command
|
||||||
|
|
||||||
# There is at least one submenu we need to go down:
|
# There is at least one submenu we need to go down:
|
||||||
else:
|
else:
|
||||||
|
|
||||||
assert self._single_command is None, "corrupt data structure in CommandMenu"
|
assert self._single_command is None, "corrupt data structure in CommandMenu"
|
||||||
assert self._cmd_tree_is_single_command == False, "corrupt data structure in CommandMenu"
|
assert (
|
||||||
|
self._cmd_tree_is_single_command is False
|
||||||
|
), "corrupt data structure in CommandMenu"
|
||||||
|
|
||||||
# Key or variable name used by argparse to store the submenu options
|
# Key or variable name used by argparse to store the submenu options
|
||||||
argparse_param = self.submenu_param # e.g.: submenu_root
|
argparse_param = self.submenu_param # e.g.: submenu_root
|
||||||
@ -251,10 +260,14 @@ class CommandTree:
|
|||||||
input("<broken>")
|
input("<broken>")
|
||||||
|
|
||||||
val = args.get(argparse_param)
|
val = args.get(argparse_param)
|
||||||
_bootstrap_logger.debug("cli - argparse command is '{}' = {}".format(argparse_param, val))
|
_bootstrap_logger.debug(
|
||||||
|
"cli - argparse command is '{}' = {}".format(argparse_param, val)
|
||||||
|
)
|
||||||
|
|
||||||
lookup = submenu.entries.get(val)
|
lookup = submenu.entries.get(val)
|
||||||
_bootstrap_logger.debug("cli - lookup, entries[{}] = {}".format(val, lookup))
|
_bootstrap_logger.debug(
|
||||||
|
"cli - lookup, entries[{}] = {}".format(val, lookup)
|
||||||
|
)
|
||||||
|
|
||||||
# pop value
|
# pop value
|
||||||
del args[argparse_param]
|
del args[argparse_param]
|
||||||
@ -297,7 +310,9 @@ class SubMenu:
|
|||||||
|
|
||||||
self.entries = {}
|
self.entries = {}
|
||||||
|
|
||||||
def register_command(self, func, cmd_name=None, func_signature=None, docstring=None):
|
def register_command(
|
||||||
|
self, func, cmd_name=None, func_signature=None, docstring=None
|
||||||
|
):
|
||||||
"""
|
"""
|
||||||
Registers a command as an entry in this submenu. Provided function is
|
Registers a command as an entry in this submenu. Provided function is
|
||||||
converted into argparse arguments and made available to the user.
|
converted into argparse arguments and made available to the user.
|
||||||
@ -371,7 +386,9 @@ class SubMenu:
|
|||||||
helptext = "default provided"
|
helptext = "default provided"
|
||||||
else:
|
else:
|
||||||
helptext = "default = '{}'".format(param.default)
|
helptext = "default = '{}'".format(param.default)
|
||||||
child_node.add_argument(key, help=helptext, nargs="?", default=param.default)
|
child_node.add_argument(
|
||||||
|
key, help=helptext, nargs="?", default=param.default
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
helptext = "required"
|
helptext = "required"
|
||||||
child_node.add_argument(key, help=helptext)
|
child_node.add_argument(key, help=helptext)
|
||||||
@ -422,7 +439,9 @@ class SubMenu:
|
|||||||
func_args = {"dest": var_name, "metavar": var_name, "required": is_required}
|
func_args = {"dest": var_name, "metavar": var_name, "required": is_required}
|
||||||
if sys.version_info.major == 3 and sys.version_info.minor < 7:
|
if sys.version_info.major == 3 and sys.version_info.minor < 7:
|
||||||
if is_required:
|
if is_required:
|
||||||
_bootstrap_logger.warn("Unable to enforce required submenu: Requires >= Python 3.7")
|
_bootstrap_logger.warn(
|
||||||
|
"Unable to enforce required submenu: Requires >= Python 3.7"
|
||||||
|
)
|
||||||
del func_args["required"]
|
del func_args["required"]
|
||||||
# END fix for Python<3.7
|
# END fix for Python<3.7
|
||||||
|
|
||||||
@ -484,7 +503,7 @@ class HelpGenerator:
|
|||||||
The 'help' text is displayed next to the command when enumerating
|
The 'help' text is displayed next to the command when enumerating
|
||||||
the submenu commands.
|
the submenu commands.
|
||||||
"""
|
"""
|
||||||
if doctext == None:
|
if doctext is None:
|
||||||
return doctext
|
return doctext
|
||||||
regex = "(.*?)[.?!]"
|
regex = "(.*?)[.?!]"
|
||||||
match = re.match(regex, doctext, re.MULTILINE | re.DOTALL)
|
match = re.match(regex, doctext, re.MULTILINE | re.DOTALL)
|
||||||
@ -498,7 +517,7 @@ class HelpGenerator:
|
|||||||
The 'description' paragraph is provided when the user requests help
|
The 'description' paragraph is provided when the user requests help
|
||||||
on a specific command.
|
on a specific command.
|
||||||
"""
|
"""
|
||||||
if doctext == None:
|
if doctext is None:
|
||||||
return doctext
|
return doctext
|
||||||
regex = "(.*?)[.?!]"
|
regex = "(.*?)[.?!]"
|
||||||
match = re.match(regex, doctext, re.MULTILINE | re.DOTALL)
|
match = re.match(regex, doctext, re.MULTILINE | re.DOTALL)
|
||||||
|
@ -3,7 +3,6 @@ import logging.config
|
|||||||
import os
|
import os
|
||||||
|
|
||||||
import appdirs
|
import appdirs
|
||||||
import colorlog
|
|
||||||
|
|
||||||
from . import _util
|
from . import _util
|
||||||
from ._bootstrap import _bootstrap_logger, _logger_name
|
from ._bootstrap import _bootstrap_logger, _logger_name
|
||||||
@ -16,7 +15,13 @@ DEFAULT_LOG_SETTINGS = {
|
|||||||
"format": "%(white)s%(name)7s%(reset)s|%(log_color)s%(message)s",
|
"format": "%(white)s%(name)7s%(reset)s|%(log_color)s%(message)s",
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"handlers": {"stderr": {"class": "logging.StreamHandler", "level": "debug", "formatter": "colored"}},
|
"handlers": {
|
||||||
|
"stderr": {
|
||||||
|
"class": "logging.StreamHandler",
|
||||||
|
"level": "debug",
|
||||||
|
"formatter": "colored",
|
||||||
|
}
|
||||||
|
},
|
||||||
"loggers": {
|
"loggers": {
|
||||||
"root": {
|
"root": {
|
||||||
"handlers": [
|
"handlers": [
|
||||||
@ -65,7 +70,9 @@ class LoggingLayer:
|
|||||||
noise for typical operation.
|
noise for typical operation.
|
||||||
"""
|
"""
|
||||||
if config_dict is None:
|
if config_dict is None:
|
||||||
_bootstrap_logger.debug("log - No application logging configuration provided. Using default")
|
_bootstrap_logger.debug(
|
||||||
|
"log - No application logging configuration provided. Using default"
|
||||||
|
)
|
||||||
config_dict = DEFAULT_LOG_SETTINGS
|
config_dict = DEFAULT_LOG_SETTINGS
|
||||||
|
|
||||||
self.transform_config(config_dict)
|
self.transform_config(config_dict)
|
||||||
@ -107,20 +114,27 @@ class LoggingLayer:
|
|||||||
if config_dict["loggers"].get("root") is not None:
|
if config_dict["loggers"].get("root") is not None:
|
||||||
config_dict["loggers"][""] = config_dict["loggers"]["root"]
|
config_dict["loggers"][""] = config_dict["loggers"]["root"]
|
||||||
del config_dict["loggers"]["root"]
|
del config_dict["loggers"]["root"]
|
||||||
except Exception as ex:
|
except Exception:
|
||||||
_bootstrap_logger.warn("was not able to find and patch root logger configuration from arguments")
|
_bootstrap_logger.warn(
|
||||||
|
"was not able to find and patch root logger configuration from arguments"
|
||||||
|
)
|
||||||
|
|
||||||
# Evaluate the full filepath of the file handler
|
# Evaluate the full filepath of the file handler
|
||||||
if "file" not in config_dict["handlers"]:
|
if "file" not in config_dict["handlers"]:
|
||||||
return
|
return
|
||||||
|
|
||||||
if os.path.abspath(config_dict["handlers"]["file"]["filename"]) == config_dict["handlers"]["file"]["filename"]:
|
if (
|
||||||
|
os.path.abspath(config_dict["handlers"]["file"]["filename"])
|
||||||
|
== config_dict["handlers"]["file"]["filename"]
|
||||||
|
):
|
||||||
# Path is already absolute
|
# Path is already absolute
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
dirname = appdirs.user_log_dir(self.appname, self.appauthor)
|
dirname = appdirs.user_log_dir(self.appname, self.appauthor)
|
||||||
_util.ensure_dir_exists(dirname)
|
_util.ensure_dir_exists(dirname)
|
||||||
log_filepath = os.path.join(dirname, config_dict["handlers"]["file"]["filename"])
|
log_filepath = os.path.join(
|
||||||
|
dirname, config_dict["handlers"]["file"]["filename"]
|
||||||
|
)
|
||||||
config_dict["handlers"]["file"]["filename"] = log_filepath
|
config_dict["handlers"]["file"]["filename"] = log_filepath
|
||||||
|
|
||||||
def _add_own_logconfig(self, config_dict):
|
def _add_own_logconfig(self, config_dict):
|
||||||
@ -133,7 +147,10 @@ class LoggingLayer:
|
|||||||
# See _bootstrap.py
|
# See _bootstrap.py
|
||||||
if os.environ.get("APPSKELLINGTON_DEBUG", None):
|
if os.environ.get("APPSKELLINGTON_DEBUG", None):
|
||||||
if _logger_name not in config_dict["loggers"]:
|
if _logger_name not in config_dict["loggers"]:
|
||||||
config_dict["loggers"][_logger_name] = {"level": "debug", "propagate": "false"}
|
config_dict["loggers"][_logger_name] = {
|
||||||
|
"level": "debug",
|
||||||
|
"propagate": "false",
|
||||||
|
}
|
||||||
else:
|
else:
|
||||||
config_dict["loggers"][_logger_name]["level"] = "debug"
|
config_dict["loggers"][_logger_name]["level"] = "debug"
|
||||||
|
|
||||||
@ -151,7 +168,7 @@ class LoggingLayer:
|
|||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
s = dict_[key]
|
s = dict_[key]
|
||||||
except KeyError as ex:
|
except KeyError:
|
||||||
raise
|
raise
|
||||||
if s == "critical":
|
if s == "critical":
|
||||||
dict_[key] = logging.CRITICAL
|
dict_[key] = logging.CRITICAL
|
||||||
|
371
poetry.lock
generated
371
poetry.lock
generated
@ -1,371 +0,0 @@
|
|||||||
# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "black"
|
|
||||||
version = "24.4.2"
|
|
||||||
description = "The uncompromising code formatter."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "black-24.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce"},
|
|
||||||
{file = "black-24.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021"},
|
|
||||||
{file = "black-24.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063"},
|
|
||||||
{file = "black-24.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb"},
|
|
||||||
{file = "black-24.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc"},
|
|
||||||
{file = "black-24.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8"},
|
|
||||||
{file = "black-24.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e"},
|
|
||||||
{file = "black-24.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7"},
|
|
||||||
{file = "black-24.4.2-py3-none-any.whl", hash = "sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c"},
|
|
||||||
{file = "black-24.4.2.tar.gz", hash = "sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
click = ">=8.0.0"
|
|
||||||
mypy-extensions = ">=0.4.3"
|
|
||||||
packaging = ">=22.0"
|
|
||||||
pathspec = ">=0.9.0"
|
|
||||||
platformdirs = ">=2"
|
|
||||||
tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""}
|
|
||||||
typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
colorama = ["colorama (>=0.4.3)"]
|
|
||||||
d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"]
|
|
||||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
|
||||||
uvloop = ["uvloop (>=0.15.2)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfgv"
|
|
||||||
version = "3.4.0"
|
|
||||||
description = "Validate configuration and produce human readable error messages."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"},
|
|
||||||
{file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "click"
|
|
||||||
version = "8.1.7"
|
|
||||||
description = "Composable command line interface toolkit"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
|
||||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "colorama"
|
|
||||||
version = "0.4.6"
|
|
||||||
description = "Cross-platform colored terminal text."
|
|
||||||
optional = false
|
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
||||||
files = [
|
|
||||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
|
||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "distlib"
|
|
||||||
version = "0.3.8"
|
|
||||||
description = "Distribution utilities"
|
|
||||||
optional = false
|
|
||||||
python-versions = "*"
|
|
||||||
files = [
|
|
||||||
{file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"},
|
|
||||||
{file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "filelock"
|
|
||||||
version = "3.15.4"
|
|
||||||
description = "A platform independent file lock."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "filelock-3.15.4-py3-none-any.whl", hash = "sha256:6ca1fffae96225dab4c6eaf1c4f4f28cd2568d3ec2a44e15a08520504de468e7"},
|
|
||||||
{file = "filelock-3.15.4.tar.gz", hash = "sha256:2207938cbc1844345cb01a5a95524dae30f0ce089eba5b00378295a17e3e90cb"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
|
||||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)", "virtualenv (>=20.26.2)"]
|
|
||||||
typing = ["typing-extensions (>=4.8)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "flake8"
|
|
||||||
version = "5.0.4"
|
|
||||||
description = "the modular source code checker: pep8 pyflakes and co"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6.1"
|
|
||||||
files = [
|
|
||||||
{file = "flake8-5.0.4-py2.py3-none-any.whl", hash = "sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248"},
|
|
||||||
{file = "flake8-5.0.4.tar.gz", hash = "sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
mccabe = ">=0.7.0,<0.8.0"
|
|
||||||
pycodestyle = ">=2.9.0,<2.10.0"
|
|
||||||
pyflakes = ">=2.5.0,<2.6.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "identify"
|
|
||||||
version = "2.6.0"
|
|
||||||
description = "File identification library for Python"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "identify-2.6.0-py2.py3-none-any.whl", hash = "sha256:e79ae4406387a9d300332b5fd366d8994f1525e8414984e1a59e058b2eda2dd0"},
|
|
||||||
{file = "identify-2.6.0.tar.gz", hash = "sha256:cb171c685bdc31bcc4c1734698736a7d5b6c8bf2e0c15117f4d469c8640ae5cf"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
license = ["ukkonen"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "isort"
|
|
||||||
version = "5.13.2"
|
|
||||||
description = "A Python utility / library to sort Python imports."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8.0"
|
|
||||||
files = [
|
|
||||||
{file = "isort-5.13.2-py3-none-any.whl", hash = "sha256:8ca5e72a8d85860d5a3fa69b8745237f2939afe12dbf656afbcb47fe72d947a6"},
|
|
||||||
{file = "isort-5.13.2.tar.gz", hash = "sha256:48fdfcb9face5d58a4f6dde2e72a1fb8dcaf8ab26f95ab49fab84c2ddefb0109"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
colors = ["colorama (>=0.4.6)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mccabe"
|
|
||||||
version = "0.7.0"
|
|
||||||
description = "McCabe checker, plugin for flake8"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "mccabe-0.7.0-py2.py3-none-any.whl", hash = "sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e"},
|
|
||||||
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "mypy-extensions"
|
|
||||||
version = "1.0.0"
|
|
||||||
description = "Type system extensions for programs checked with the mypy type checker."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
files = [
|
|
||||||
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
|
|
||||||
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "nodeenv"
|
|
||||||
version = "1.9.1"
|
|
||||||
description = "Node.js virtual environment builder"
|
|
||||||
optional = false
|
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
||||||
files = [
|
|
||||||
{file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"},
|
|
||||||
{file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "packaging"
|
|
||||||
version = "24.1"
|
|
||||||
description = "Core utilities for Python packages"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
|
|
||||||
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pathspec"
|
|
||||||
version = "0.12.1"
|
|
||||||
description = "Utility library for gitignore style pattern matching of file paths."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"},
|
|
||||||
{file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "platformdirs"
|
|
||||||
version = "4.2.2"
|
|
||||||
description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"},
|
|
||||||
{file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"]
|
|
||||||
test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"]
|
|
||||||
type = ["mypy (>=1.8)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pre-commit"
|
|
||||||
version = "3.5.0"
|
|
||||||
description = "A framework for managing and maintaining multi-language pre-commit hooks."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "pre_commit-3.5.0-py2.py3-none-any.whl", hash = "sha256:841dc9aef25daba9a0238cd27984041fa0467b4199fc4852e27950664919f660"},
|
|
||||||
{file = "pre_commit-3.5.0.tar.gz", hash = "sha256:5804465c675b659b0862f07907f96295d490822a450c4c40e747d0b1c6ebcb32"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
cfgv = ">=2.0.0"
|
|
||||||
identify = ">=1.0.0"
|
|
||||||
nodeenv = ">=0.11.1"
|
|
||||||
pyyaml = ">=5.1"
|
|
||||||
virtualenv = ">=20.10.0"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pycodestyle"
|
|
||||||
version = "2.9.1"
|
|
||||||
description = "Python style guide checker"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "pycodestyle-2.9.1-py2.py3-none-any.whl", hash = "sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b"},
|
|
||||||
{file = "pycodestyle-2.9.1.tar.gz", hash = "sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyflakes"
|
|
||||||
version = "2.5.0"
|
|
||||||
description = "passive checker of Python programs"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"},
|
|
||||||
{file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "pyyaml"
|
|
||||||
version = "6.0.1"
|
|
||||||
description = "YAML parser and emitter for Python"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
files = [
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"},
|
|
||||||
{file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"},
|
|
||||||
{file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},
|
|
||||||
{file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"},
|
|
||||||
{file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"},
|
|
||||||
{file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"},
|
|
||||||
{file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"},
|
|
||||||
{file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"},
|
|
||||||
{file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tomli"
|
|
||||||
version = "2.0.1"
|
|
||||||
description = "A lil' TOML parser"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
|
|
||||||
{file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typing-extensions"
|
|
||||||
version = "4.12.2"
|
|
||||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
files = [
|
|
||||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
|
||||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "virtualenv"
|
|
||||||
version = "20.26.3"
|
|
||||||
description = "Virtual Python Environment builder"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"},
|
|
||||||
{file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
distlib = ">=0.3.7,<1"
|
|
||||||
filelock = ">=3.12.2,<4"
|
|
||||||
platformdirs = ">=3.9.1,<5"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"]
|
|
||||||
test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"]
|
|
||||||
|
|
||||||
[metadata]
|
|
||||||
lock-version = "2.0"
|
|
||||||
python-versions = "^3.8"
|
|
||||||
content-hash = "c20dac4ba2095b38a3009c1520b6cd1e9865cc50dff8559ddd767403898406c6"
|
|
@ -1,49 +1,45 @@
|
|||||||
[tool.poetry]
|
|
||||||
name = "app_skellington"
|
|
||||||
version = "0.1.0"
|
|
||||||
description = "app_skellington CLI framework"
|
|
||||||
authors = [
|
|
||||||
"Mathew Guest <mathew.guest@davita.com>",
|
|
||||||
]
|
|
||||||
license = "Creative Commons"
|
|
||||||
readme = "README.md"
|
|
||||||
homepage = "https://zavage-software.com"
|
|
||||||
repository = "https://git-mirror.zavage.net/Zavage-Software/app_skellington"
|
|
||||||
documentation = "https://git-mirror.zavage.net/Zavage-Software/app_skellington"
|
|
||||||
keywords = [""]
|
|
||||||
|
|
||||||
packages = [{ include = "app_skellington" }]
|
|
||||||
include = [
|
|
||||||
"README.md",
|
|
||||||
]
|
|
||||||
|
|
||||||
# [tool.poetry.scripts]
|
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.dependencies]
|
|
||||||
python = "^3.8"
|
|
||||||
# psycopg2-binary = "^2.9"
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
|
||||||
black = "*"
|
|
||||||
pre-commit = "*"
|
|
||||||
isort = "*"
|
|
||||||
flake8 = "*"
|
|
||||||
#pytest = "^7.2"
|
|
||||||
#Sphinx = "^5.3.0"
|
|
||||||
#sphinx-rtd-theme = "^1.3.0"
|
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry-core>=1.0.0"]
|
requires = ["setuptools>=45", "setuptools_scm[toml]>=6.2"]
|
||||||
build-backend = "poetry.core.masonry.api"
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
[tool.black]
|
[project]
|
||||||
line-length = 120
|
name = "app_skellington"
|
||||||
target-version = ['py38']
|
dynamic = ["version"]
|
||||||
|
license = {file = "LICENSE.txt"}
|
||||||
|
readme = "README.md"
|
||||||
|
description = "app_skellington CLI framework"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
dependencies = [
|
||||||
|
"appdirs",
|
||||||
|
"configobj",
|
||||||
|
"colorlog"
|
||||||
|
]
|
||||||
|
authors = [
|
||||||
|
{name = "Mathew Guest", email = "mat@zavage.net"}
|
||||||
|
]
|
||||||
|
keywords = ["cli", "logging", "application"]
|
||||||
|
classifiers = [
|
||||||
|
"Programming Language :: Python :: 3",
|
||||||
|
"License :: OSI Approved :: MIT License",
|
||||||
|
"Operating System :: OS Independent"
|
||||||
|
]
|
||||||
|
|
||||||
[tool.isort]
|
|
||||||
multi_line_output = 3
|
[project.urls]
|
||||||
combine_as_imports = true
|
homepage = "https://zavage-software.com/portfolio/app_skellington"
|
||||||
include_trailing_comma = true
|
repository = "https://git-repos.zavage.net/Zavage-Software/app_skellington"
|
||||||
force_grid_wrap = 3
|
documentation = "https://git-repos.zavage.net/Zavage-Software/app_skellington"
|
||||||
ensure_newline_before_comments = true
|
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
dev = [
|
||||||
|
"black",
|
||||||
|
"pre-commit",
|
||||||
|
"isort",
|
||||||
|
"flake8"
|
||||||
|
]
|
||||||
|
|
||||||
|
[tool.setuptools_scm]
|
||||||
|
version_file = "app_skellington/_version.py"
|
||||||
|
version_scheme = "release-branch-semver"
|
||||||
|
local_scheme = "node-and-date"
|
||||||
|
66
setup.py
66
setup.py
@ -1,66 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
#
|
|
||||||
# Usage:
|
|
||||||
#
|
|
||||||
# First, enable the python environment you want to install to, or if installing
|
|
||||||
# system-wide then ensure you're logged in with sufficient permissions
|
|
||||||
# (admin or root to install to system directories)
|
|
||||||
#
|
|
||||||
# installation:
|
|
||||||
#
|
|
||||||
# $ ./setup.py install
|
|
||||||
#
|
|
||||||
# de-installation:
|
|
||||||
#
|
|
||||||
# $ pip uninstall app_skellington
|
|
||||||
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
from setuptools import setup
|
|
||||||
|
|
||||||
__project__ = "app_skellington"
|
|
||||||
__version__ = "0.1.1"
|
|
||||||
__description__ = "A high-powered command line menu framework."
|
|
||||||
|
|
||||||
long_description = __description__
|
|
||||||
readme_filepath = os.path.join(os.path.abspath(os.path.dirname(__file__)), "README.md")
|
|
||||||
with open(readme_filepath, encoding="utf-8") as fp:
|
|
||||||
long_description = fp.read()
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name=__project__,
|
|
||||||
version=__version__,
|
|
||||||
description="A high-powered command line menu framework.",
|
|
||||||
long_description=long_description,
|
|
||||||
author="Mathew Guest",
|
|
||||||
author_email="t3h.zavage@gmail.com",
|
|
||||||
url="https://git-mirror.zavage.net/Mirror/app_skellington",
|
|
||||||
license="MIT",
|
|
||||||
python_requires=">=3",
|
|
||||||
classifiers=[
|
|
||||||
"Development Status :: 3 - Alpha",
|
|
||||||
"Environment :: Console",
|
|
||||||
"Framework :: Pytest",
|
|
||||||
"Intended Audience :: Developers",
|
|
||||||
"Intended Audience :: System Administrators",
|
|
||||||
"License :: OSI Approved :: MIT License",
|
|
||||||
"Natural Language :: English",
|
|
||||||
"Operating System :: MacOS",
|
|
||||||
"Operating System :: Microsoft",
|
|
||||||
"Operating System :: Microsoft :: Windows",
|
|
||||||
"Operating System :: OS Independent",
|
|
||||||
"Operating System :: POSIX",
|
|
||||||
"Operating System :: POSIX :: Linux",
|
|
||||||
"Topic :: Software Development :: Libraries",
|
|
||||||
"Topic :: Utilities",
|
|
||||||
],
|
|
||||||
# Third-party dependencies; will be automatically installed
|
|
||||||
install_requires=(
|
|
||||||
"appdirs",
|
|
||||||
"configobj",
|
|
||||||
"colorlog",
|
|
||||||
),
|
|
||||||
# Local packages to be installed (our packages)
|
|
||||||
packages=("app_skellington",),
|
|
||||||
)
|
|
@ -32,12 +32,18 @@ def sample_invalid_configspec_filepath():
|
|||||||
class TestConfig_e2e:
|
class TestConfig_e2e:
|
||||||
def test_allows_reading_ini_and_no_spec(self, sample_configini_filepath):
|
def test_allows_reading_ini_and_no_spec(self, sample_configini_filepath):
|
||||||
cfg = Config(configini_filepath=sample_configini_filepath)
|
cfg = Config(configini_filepath=sample_configini_filepath)
|
||||||
assert cfg["root_option"] == "root_option_val", "expecting default from config.spec (didnt get)"
|
assert (
|
||||||
assert cfg["app"]["sub_option"] == "sub_option_val", "expecting default for sub option"
|
cfg["root_option"] == "root_option_val"
|
||||||
|
), "expecting default from config.spec (didnt get)"
|
||||||
|
assert (
|
||||||
|
cfg["app"]["sub_option"] == "sub_option_val"
|
||||||
|
), "expecting default for sub option"
|
||||||
|
|
||||||
def test_allows_reading_spec_and_no_ini(self, sample_configspec_filepath):
|
def test_allows_reading_spec_and_no_ini(self, sample_configspec_filepath):
|
||||||
cfg = Config(configspec_filepath=sample_configspec_filepath)
|
cfg = Config(configspec_filepath=sample_configspec_filepath)
|
||||||
assert cfg["root_option"] == "def_string", "expecting default from config.spec (didnt get)"
|
assert (
|
||||||
|
cfg["root_option"] == "def_string"
|
||||||
|
), "expecting default from config.spec (didnt get)"
|
||||||
|
|
||||||
# NOTE(MG) Changed the functionality to not do it this way.
|
# NOTE(MG) Changed the functionality to not do it this way.
|
||||||
# def test_constructor_fails_with_invalid_spec(
|
# def test_constructor_fails_with_invalid_spec(
|
||||||
@ -65,7 +71,9 @@ class TestConfig_e2e:
|
|||||||
assert cfg["root_option"] == "newval"
|
assert cfg["root_option"] == "newval"
|
||||||
|
|
||||||
cfg["app"]["sub_option"] = "another_new_val"
|
cfg["app"]["sub_option"] = "another_new_val"
|
||||||
assert cfg["app"]["sub_option"] == "another_new_val", "expecting default for sub option"
|
assert (
|
||||||
|
cfg["app"]["sub_option"] == "another_new_val"
|
||||||
|
), "expecting default for sub option"
|
||||||
|
|
||||||
def test_can_set_option_without_config(self):
|
def test_can_set_option_without_config(self):
|
||||||
cfg = Config()
|
cfg = Config()
|
||||||
@ -78,5 +86,7 @@ class TestConfig_e2e:
|
|||||||
|
|
||||||
def test_uses_spec_as_defaults(self, sample_configspec_filepath):
|
def test_uses_spec_as_defaults(self, sample_configspec_filepath):
|
||||||
cfg = Config(configspec_filepath=sample_configspec_filepath)
|
cfg = Config(configspec_filepath=sample_configspec_filepath)
|
||||||
assert cfg["root_option"] == "def_string", "expecting default from config.spec (didnt get)"
|
assert (
|
||||||
|
cfg["root_option"] == "def_string"
|
||||||
|
), "expecting default from config.spec (didnt get)"
|
||||||
assert cfg["app"]["sub_option"] == "def_sub", "expecting default for sub option"
|
assert cfg["app"]["sub_option"] == "def_sub", "expecting default for sub option"
|
||||||
|
Loading…
Reference in New Issue
Block a user