Compare commits

..

1 Commits

10 changed files with 37 additions and 31 deletions

@ -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.
- Compatible with Linux, Windows, and Mac. Try to be compatible as possible otherwise. - Compatable 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_DEBUG' environment variable to any value which turns Set 'APPSKELLINGTON_ENABLE_LOGGING' environment variable to any value which turns
on AppSkellington logger. For example, on AppSkellington-level logging. For example,
APPSKELLINGTON_DEBUG=1 <executable> APPSKELLINGTON_DEBUG=1 <executable>

@ -1,3 +1,6 @@
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,6 +4,8 @@ import inspect
import os import os
import sys import sys
from . import _util
def eprint(*args, **kwargs): def eprint(*args, **kwargs):
""" """
@ -28,7 +30,7 @@ def does_file_exist(filepath):
instant in execution. instant in execution.
""" """
try: try:
open(filepath, "r") fp = open(filepath, "r")
return True return True
except FileNotFoundError as ex: except FileNotFoundError as ex:
return False return False

@ -1,6 +1,9 @@
import collections
import functools import functools
import inspect import inspect
import logging
import os import os
import sys
import appdirs import appdirs
@ -102,7 +105,6 @@ 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):
@ -130,7 +132,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") -> str: def _get_config_filepath(self, app_name, app_author, config_filename="config.ini"):
""" """
Attempt to find config.ini in the user's config directory. Attempt to find config.ini in the user's config directory.
@ -142,7 +144,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: str = "config.spec") -> str: def _get_configspec_filepath(self, configspec_filename="config.spec"):
""" """
Attempt to find config.spec inside the installed package directory. Attempt to find config.spec inside the installed package directory.
""" """
@ -163,7 +165,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) -> bool: def load_command(self):
args, unk, success = self.cli.parse() args, unk, success = self.cli.parse()
if not success: if not success:
return False return False
@ -181,13 +183,13 @@ class ApplicationContainer:
print("Failure: No command specified.") print("Failure: No command specified.")
def interactive_shell(self): def interactive_shell(self):
raise NotImplementedError() pass
def invoke_from_cli(self): def invoke_from_cli(self):
self.invoke_command() self.invoke_command()
def usage(self): def usage(self):
raise NotImplementedError() pass
# Applications need a default usage # Applications need a default usage

@ -4,10 +4,15 @@
# 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
@ -95,15 +100,14 @@ 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")
# TODO(MG) initial code was present but unreachable. is an error in coding. self.load_config()
# 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:
_bootstrap_logger.error("failed to __containers__ on key (%s): %s", key, ex) pass
def __delitem__(self, key): def __delitem__(self, key):
""" """
@ -113,7 +117,7 @@ class Config:
try: try:
del self[key] del self[key]
except KeyError as ex: except KeyError as ex:
_bootstrap_logger.error("failed to __delitem__ on key (%s): %s", key, ex) pass
def __getitem__(self, key): def __getitem__(self, key):
""" """
@ -127,7 +131,6 @@ 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):
@ -148,16 +151,9 @@ 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) -> bool: def load_config(self, configspec_filepath=None, configini_filepath=None):
"""
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
@ -204,7 +200,7 @@ class Config:
_bootstrap_logger.error(msg) _bootstrap_logger.error(msg)
return False return False
except Exception as ex: except Exception as ex:
_bootstrap_logger.error(ex) print(ex)
def _validate_config_against_spec(self): def _validate_config_against_spec(self):
config_spec = self.configspec_filepath config_spec = self.configspec_filepath
@ -238,7 +234,6 @@ 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,8 +1,11 @@
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
@ -66,7 +69,7 @@ class CommandTree:
self._single_command = None self._single_command = None
def print_tree(self): def print_tree(self):
raise NotImplementedError() raise NotImplemented
def add_argument(self, *args, **kwargs): def add_argument(self, *args, **kwargs):
""" """

@ -3,6 +3,7 @@ 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/portfolio/app_skellington" homepage = "https://zavage-software.com"
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="mat@zavage.net", author_email="t3h.zavage@gmail.com",
url="https://git-mirror.zavage.net/zavage-software/app_skellington", url="https://git-mirror.zavage.net/Mirror/app_skellington",
license="MIT", license="MIT",
python_requires=">=3", python_requires=">=3",
classifiers=[ classifiers=[