Skip to content

Commit

Permalink
Merge branch 'release/2.4.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
glentner committed Jun 3, 2021
2 parents 14ec250 + d441ad9 commit b87840d
Show file tree
Hide file tree
Showing 17 changed files with 432 additions and 481 deletions.
2 changes: 1 addition & 1 deletion Pipfile
Expand Up @@ -22,4 +22,4 @@ twine = ">=3.2.0"
cmdkit = {editable = true, path = "."}

[requires]
python_version = "3.8.7"
python_version = "3.9"
599 changes: 317 additions & 282 deletions Pipfile.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion README.rst
Expand Up @@ -25,7 +25,7 @@ A library for developing command-line applications in Python.

.. image:: https://github.com/glentner/CmdKit/workflows/tests/badge.svg
:target: https://github.com/glentner/cmdkit/actions
:alt: Downloads
:alt: Pytest

|
Expand Down
13 changes: 3 additions & 10 deletions cmdkit/__init__.py
@@ -1,12 +1,5 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Package initialization for CmdKit."""

Expand All @@ -16,5 +9,5 @@
__license__, __copyright__, __description__)


# top-level logger
# null-handler for library
logging.getLogger(__name__).addHandler(logging.NullHandler())
15 changes: 4 additions & 11 deletions cmdkit/__meta__.py
@@ -1,20 +1,13 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Metadata for CmdKit package."""


__pkgname__ = 'cmdkit'
__version__ = '2.3.0'
__version__ = '2.4.0'
__authors__ = 'Geoffrey Lentner'
__contact__ = 'glentner@purdue.edu'
__license__ = 'Apache License'
__copyright__ = 'Copyright (c) Geoffrey Lentner 2019. All Rights Reserved.'
__copyright__ = 'Geoffrey Lentner 2019-2021'
__description__ = 'A command-line utility toolkit for Python.'
17 changes: 4 additions & 13 deletions cmdkit/app.py
@@ -1,16 +1,7 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.

"""
Application class implementation.
"""
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Application class implementation."""


# type annotations
Expand Down
15 changes: 4 additions & 11 deletions cmdkit/cli.py
@@ -1,13 +1,5 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.

# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""
Implements the `Interface` class.
Expand All @@ -19,11 +11,12 @@ class takes a pre-constructed usage and help string and uses those instead.
instead of trying to exit the program immediately.
"""


# standard libs
import argparse as _argparse

# public interface
__all__ = ['Interface', ]
__all__ = ['Interface', 'ArgumentError', ]

# elevate to this module
Namespace = _argparse.Namespace
Expand Down
71 changes: 30 additions & 41 deletions cmdkit/config.py
@@ -1,12 +1,5 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""
Configuration management. Classes and interfaces for managing application level
Expand All @@ -17,7 +10,7 @@

# type annotations
from __future__ import annotations
from typing import Tuple, IO, Dict, TypeVar, Callable, Union, Iterable, Optional, Any
from typing import IO, Dict, TypeVar, Callable, Union, Iterable, Optional, Any

# standard libs
import os
Expand All @@ -36,43 +29,39 @@
DictKeyIterator: type = type(iter({}))


T = TypeVar('T')
def _as_namespace(ns: T) -> Union[T, Namespace]:
"""If `ns` is a mappable, coerce to Namespace, recursively, otherwise pass."""
return ns if not isinstance(ns, Mapping) else Namespace({k: _as_namespace(v) for k, v in dict(ns).items()})


def _as_dict(ns: NSCoreMixin) -> dict:
"""If `ns` is a mappable, coerce to dict, recursively, otherwise pass."""
return {k: v if not isinstance(v, Mapping) else _as_dict(v) for k, v in dict(ns).items()}


class NSCoreMixin(dict):
"""Core namespace mechanics used by `Namespace` and `Configuration`."""

def __init__(self, *args: Union[Iterable, Mapping], **kwargs: Any) -> None:
"""Initialize from same signature as `dict`."""
super().__init__(*args, **kwargs)

def __getitem__(self, key: str) -> Any:
"""Like `dict.__getitem__` but return Namespace if value is a mappable."""
value = super().__getitem__(key)
if isinstance(value, Mapping):
return Namespace(value)
else:
return value
super().__init__()
for k, v in dict(*args, **kwargs).items():
self[k] = _as_namespace(v)

def __setitem__(self, key: str, value: Any) -> None:
"""Strip special type if `value` is Namespace."""
if isinstance(value, Mapping):
super().__setitem__(key, dict(value))
else:
"""Strip special type if `value` is Namespace-like."""
if not isinstance(value, Mapping):
super().__setitem__(key, value)

def get(self, key: Any, default: Any = None) -> Optional[Any]:
"""Like `dict.get` but return Namespace if value is a mappable."""
value = super().get(key, default)
if isinstance(value, Mapping):
return Namespace(value)
else:
return value
super().__setitem__(key, _as_namespace(dict(value)))

def items(self) -> Iterable[Tuple[str, Any]]:
"""Yield key, value pairs."""
for key, value in super().items():
if isinstance(value, Mapping):
yield key, Namespace(value)
else:
yield key, value
def __setattr__(self, name: str, value: Any) -> None:
"""Alias for index notation (if already present)."""
if name in self:
self[name] = value
else:
super().__setattr__(name, value)

@classmethod
def _depth_first_update(cls, original: dict, new: dict) -> dict:
Expand All @@ -93,7 +82,7 @@ def update(self, *args, **kwargs) -> None:

def __getattr__(self, item: str) -> Any:
"""
Get attribute by calling :meth:`__getitem__`.
Alias for index notation.
Transparently expand `_env` and `_eval` variants.
"""
variants = [f'{item}_env', f'{item}_eval']
Expand Down Expand Up @@ -130,8 +119,7 @@ def _expand_attr_eval(self, item: str) -> str:

def __repr__(self) -> str:
"""Convert to string representation."""
original = super().__repr__()
return f'{self.__class__.__name__}({original})'
return f'{self.__class__.__name__}({repr(_as_dict(self))})'


class Namespace(NSCoreMixin):
Expand All @@ -141,6 +129,7 @@ class Namespace(NSCoreMixin):
Example:
>>> ns = Namespace({'a': {'x': 1, 'y': 2}, 'b': 3})
>>> ns.update({'a': {'x': 4, 'z': 5}})
>>> ns
Namespace({'a': {'x': 4, 'y': 2, 'z': 5}, 'b': 3})
>>> Namespace.from_local('config.toml', ignore_if_missing=True)
Expand Down Expand Up @@ -200,7 +189,7 @@ def from_json(cls, path_or_file: Union[str, IO], **options) -> Namespace:

def to_dict(self) -> Dict[str, Any]:
"""Explicitly coerce a Namespace to dictionary."""
return dict(self)
return _as_dict(self)

def to_local(self, filepath: str, **options) -> None:
"""Output to local file. Format based on file extension."""
Expand Down
18 changes: 5 additions & 13 deletions cmdkit/service/agent.py
@@ -1,16 +1,8 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.

"""
Agent implementation.
"""
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Agent class implementation."""


# standard libs
import time
Expand Down
11 changes: 2 additions & 9 deletions cmdkit/service/daemon.py
@@ -1,12 +1,5 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Implementation of abstract base class for daemon services."""

Expand Down
17 changes: 4 additions & 13 deletions cmdkit/service/service.py
@@ -1,16 +1,7 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.

"""
Implementation of Service class.
"""
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Service class implementation."""

# internal libs
from .daemon import Daemon
Expand Down
33 changes: 18 additions & 15 deletions docs/source/api/config.rst
Expand Up @@ -6,21 +6,9 @@

|
Configuration management. Classes and interfaces for management application level
parameters. Get a runtime configuration with a namespace-like interface from both
local files and your environment.

|
.. note::

Because of an implementation detail regarding the way nested members are
handled recursively by these data structures, in-place assignments of such
nested members will not have an effect.

These objects are then to be treated as read-only in the sense that they can
only allow :func:`update` (for :class:`Namespace`) and :func:`extend`
(for :class:`Configuration`).
Classes and interfaces for managing application level configuration parameters.
Get a runtime configuration with a namespace-like interface from both
local files and environment variables with appropriate precedent.

|
Expand Down Expand Up @@ -102,6 +90,21 @@ local files and your environment.

|
.. note::

Because of an implementation detail regarding the way the :class:`Configuration`
class is implemented, using the :func:`update` method directly will have the intended
effect on the immediate representation of the structure, but knowledge of where that
change occurred will be lost.

Similarly, directly modifying parameters will work as expected with the exception that
the now current value will lose its provenance.

**This behavior is not considered part of the public API and may in future releases be
changed without notice and is not considered a major change.**

|
.. toctree::
:maxdepth: 3
:hidden:
12 changes: 3 additions & 9 deletions setup.py
@@ -1,12 +1,5 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Build and installation script for CmdKit."""

Expand Down Expand Up @@ -57,6 +50,7 @@
'Programming Language :: Python :: 3.7',
'Programming Language :: Python :: 3.8',
'Programming Language :: Python :: 3.9',
'Programming Language :: Python :: 3.10',
'License :: OSI Approved :: Apache Software License', ],
entry_points = {'console_scripts': []},
install_requires = DEPENDENCIES,
Expand Down
13 changes: 3 additions & 10 deletions tests/__init__.py
@@ -1,11 +1,4 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Unit tests for CmdKit."""
"""Unit tests for CmdKit."""
11 changes: 2 additions & 9 deletions tests/test_app.py
@@ -1,12 +1,5 @@
# This program is free software: you can redistribute it and/or modify it under the
# terms of the Apache License (v2.0) as published by the Apache Software Foundation.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE. See the Apache License for more details.
#
# You should have received a copy of the Apache License along with this program.
# If not, see <https://www.apache.org/licenses/LICENSE-2.0>.
# SPDX-FileCopyrightText: 2021 CmdKit Developers
# SPDX-License-Identifier: Apache-2.0

"""Unit tests for `cmdkit.app` behavior and interfaces."""

Expand Down

0 comments on commit b87840d

Please sign in to comment.