Compare commits

...

3 Commits

10 changed files with 31 additions and 37 deletions

0
CHANGELOG.md Normal file

@ -10,7 +10,7 @@ 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 Application Configuration
@ -47,8 +47,8 @@ argument.
Debug - Turn on Logging Debug - Turn on Logging
----------------------- -----------------------
Set 'APPSKELLINGTON_ENABLE_LOGGING' environment variable to any value which turns Set 'APPSKELLINGTON_DEBUG' environment variable to any value which turns
on AppSkellington-level logging. For example, on AppSkellington logger. For example,
APPSKELLINGTON_DEBUG=1 <executable> APPSKELLINGTON_DEBUG=1 <executable>

@ -1,6 +1,3 @@
import logging
import sys
from .app_container import * from .app_container import *
from .cfg import * from .cfg import *
from .cli import * from .cli import *

@ -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,7 +28,7 @@ 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 as ex:
return False return False

@ -1,9 +1,6 @@
import collections
import functools import functools
import inspect import inspect
import logging
import os import os
import sys
import appdirs import appdirs
@ -105,6 +102,7 @@ class ApplicationContainer:
except KeyError as ex: except KeyError as ex:
msg = "failed to inject service: {}".format(service_name) msg = "failed to inject service: {}".format(service_name)
_bootstrap_logger.critical(msg) _bootstrap_logger.critical(msg)
_bootstrap_logger.debug(ex)
raise ServiceNotFound raise ServiceNotFound
def __setitem__(self, service_name, value): def __setitem__(self, service_name, value):
@ -132,7 +130,7 @@ class ApplicationContainer:
dependencies.append(self[dep_name]) dependencies.append(self[dep_name])
return model_constructor(*dependencies) return model_constructor(*dependencies)
def _get_config_filepath(self, app_name, app_author, config_filename="config.ini"): def _get_config_filepath(self, app_name, app_author, config_filename="config.ini") -> str:
""" """
Attempt to find config.ini in the user's config directory. Attempt to find config.ini in the user's config directory.
@ -144,7 +142,7 @@ class ApplicationContainer:
_bootstrap_logger.info("default config filepath calculated to be: %s", filepath) _bootstrap_logger.info("default config filepath calculated to be: %s", filepath)
return filepath return filepath
def _get_configspec_filepath(self, configspec_filename="config.spec"): def _get_configspec_filepath(self, configspec_filename: str = "config.spec") -> str:
""" """
Attempt to find config.spec inside the installed package directory. Attempt to find config.spec inside the installed package directory.
""" """
@ -165,7 +163,7 @@ class ApplicationContainer:
return functools.partial(self._construct_model, constructor, *cls_dependencies) return functools.partial(self._construct_model, constructor, *cls_dependencies)
def load_command(self): def load_command(self) -> bool:
args, unk, success = self.cli.parse() args, unk, success = self.cli.parse()
if not success: if not success:
return False return False
@ -183,13 +181,13 @@ class ApplicationContainer:
print("Failure: No command specified.") print("Failure: No command specified.")
def interactive_shell(self): def interactive_shell(self):
pass raise NotImplementedError()
def invoke_from_cli(self): def invoke_from_cli(self):
self.invoke_command() self.invoke_command()
def usage(self): def usage(self):
pass raise NotImplementedError()
# Applications need a default usage # Applications need a default usage

@ -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
@ -100,14 +95,15 @@ class Config:
_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() # TODO(MG) initial code was present but unreachable. is an error in coding.
# self.load_config()
def __contains__(self, key): def __contains__(self, key):
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 as ex:
pass _bootstrap_logger.error("failed to __containers__ on key (%s): %s", key, ex)
def __delitem__(self, key): def __delitem__(self, key):
""" """
@ -117,7 +113,7 @@ class Config:
try: try:
del self[key] del self[key]
except KeyError as ex: except KeyError as ex:
pass _bootstrap_logger.error("failed to __delitem__ on key (%s): %s", key, ex)
def __getitem__(self, key): def __getitem__(self, key):
""" """
@ -131,6 +127,7 @@ class Config:
# 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 as ex:
_bootstrap_logger.error("failed to __getitem__ on key (%s): %s", key, ex)
raise raise
def __setitem__(self, key, value): def __setitem__(self, key, value):
@ -151,9 +148,16 @@ class Config:
v = self.__getitem__(key) v = self.__getitem__(key)
return v return v
except KeyError as ex: except KeyError as ex:
_bootstrap_logger.error("failed to retrieve config key (%s): %s", key, ex)
return default return default
def load_config(self, configspec_filepath=None, configini_filepath=None): def load_config(self, configspec_filepath=None, configini_filepath=None) -> bool:
"""
Loads config from file, validating against configspec.
Returns:
bool: success status of command and validation.
"""
# Set new arguments if were passed in: # Set new arguments if were passed in:
if configspec_filepath is not None: if configspec_filepath is not None:
self.configspec_filepath = configspec_filepath self.configspec_filepath = configspec_filepath
@ -200,7 +204,7 @@ class Config:
_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)
def _validate_config_against_spec(self): def _validate_config_against_spec(self):
config_spec = self.configspec_filepath config_spec = self.configspec_filepath
@ -234,6 +238,7 @@ class Config:
return False return False
except ValueError as ex: except ValueError as ex:
_bootstrap_logger.error("cfg - Failed while validating config against spec. ") _bootstrap_logger.error("cfg - Failed while validating config against spec. ")
_bootstrap_logger.debug(ex)
return False return False
def _validate_parse_errors(self, test_results): def _validate_parse_errors(self, test_results):

@ -1,11 +1,8 @@
import argparse import argparse
import inspect import inspect
import logging
import re import re
import sys import sys
import app_skellington
from . import app_container from . import app_container
from ._bootstrap import _bootstrap_logger from ._bootstrap import _bootstrap_logger
@ -69,7 +66,7 @@ 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):
""" """

@ -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

@ -7,9 +7,9 @@ authors = [
] ]
license = "Creative Commons" license = "Creative Commons"
readme = "README.md" readme = "README.md"
homepage = "https://zavage-software.com" homepage = "https://zavage-software.com/portfolio/app_skellington"
repository = "https://git-mirror.zavage.net/Zavage-Software/app_skellington" repository = "https://git-mirror.zavage.net/zavage-software/app_skellington"
documentation = "https://git-mirror.zavage.net/Zavage-Software/app_skellington" documentation = "https://git-mirror.zavage.net/zavage-software/app_skellington"
keywords = [""] keywords = [""]
packages = [{ include = "app_skellington" }] packages = [{ include = "app_skellington" }]

@ -34,8 +34,8 @@ setup(
description="A high-powered command line menu framework.", description="A high-powered command line menu framework.",
long_description=long_description, long_description=long_description,
author="Mathew Guest", author="Mathew Guest",
author_email="t3h.zavage@gmail.com", author_email="mat@zavage.net",
url="https://git-mirror.zavage.net/Mirror/app_skellington", url="https://git-mirror.zavage.net/zavage-software/app_skellington",
license="MIT", license="MIT",
python_requires=">=3", python_requires=">=3",
classifiers=[ classifiers=[