Skip to content

Commit 6d05af1

Browse files
authored
Merge pull request #16 from sarnold/cleanup-bits
more config
2 parents 2820b29 + 9614f5d commit 6d05af1

11 files changed

Lines changed: 110 additions & 62 deletions

File tree

.github/workflows/coverage.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ jobs:
125125
126126
cov_data:
127127
name: Generate test coverage data
128-
runs-on: ubuntu-20.04
128+
runs-on: ubuntu-22.04
129129
permissions:
130130
contents: read
131131
pull-requests: write
@@ -137,7 +137,7 @@ jobs:
137137
coverage: ${{ steps.coverage.outputs.coverage }}
138138
coverage-rounded-display: ${{ steps.coverage.outputs.coverage-rounded-display }}
139139
env:
140-
PLATFORM: ubuntu-20.04
140+
PLATFORM: ubuntu-22.04
141141
PYTHON: '3.11'
142142
PYTHONIOENCODING: utf-8
143143
PIP_DOWNLOAD_CACHE: ${{ github.workspace }}/../.pip_download_cache

.pre-commit-config.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ repos:
4848
- --follow-imports=normal
4949
- --install-types
5050
- --non-interactive
51-
- --ignore-missing-imports
51+
additional_dependencies:
52+
- "munch[yaml]"
53+
- "munch-stubs @ git+https://github.com/VCTLabs/munch-stubs.git@main"
5254
files: procman/
5355

5456
- repo: "https://github.com/asottile/blacken-docs"

docs/source/conf.py

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
import os
1414
import sys
1515

16+
from datetime import datetime
17+
1618
if sys.version_info < (3, 8):
1719
from importlib_metadata import version
1820
else:
@@ -22,20 +24,22 @@
2224

2325
# -- Project information -----------------------------------------------------
2426

27+
# The full version, including alpha/beta/rc tags with setuptols-scm
28+
# workaround for extra-long dirty version string
29+
release = version('procman').split("+")[0]
30+
# screw the short X.Y version.
31+
version = release
32+
2533
project = 'procman'
26-
copyright = '2023, Stephen L Arnold'
2734
author = 'Stephen Arnold'
28-
29-
# The full version, including alpha/beta/rc tags
30-
release = version('procman')
31-
# The short X.Y version.
32-
version = '.'.join(release.split('.')[:2])
35+
copyright = '2023 - ' + str(datetime.now().year) + f' {author}'
3336

3437
# -- General configuration ------------------------------------------------
3538

3639
# If your documentation needs a minimal Sphinx version, state it here.
3740
#
3841
# needs_sphinx = '1.0'
42+
#needs_sphinx = "8.2.0"
3943

4044
# Add any Sphinx extension module names here, as strings. They can be
4145
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
@@ -44,27 +48,33 @@
4448
'sphinx_git',
4549
'sphinxcontrib.apidoc',
4650
'sphinx.ext.autodoc',
51+
'sphinx.ext.autodoc.typehints',
4752
'sphinx.ext.doctest',
48-
'sphinx.ext.intersphinx',
4953
'sphinx.ext.todo',
5054
'sphinx.ext.coverage',
5155
'sphinx.ext.viewcode',
5256
'recommonmark',
5357
]
5458

55-
apidoc_module_dir = '../../procman/'
59+
# sphinxcontrib.apidoc
60+
apidoc_module_dir = '../../procman'
5661
apidoc_output_dir = 'api'
5762
apidoc_excluded_paths = ['tests']
63+
apidoc_include_private = True
5864
apidoc_separate_modules = True
5965

66+
autodoc_typehints = 'description'
67+
6068
# Add any paths that contain templates here, relative to this directory.
6169
templates_path = ['_templates']
6270

6371
# The suffix(es) of source filenames.
6472
# You can specify multiple suffix as a list of string:
6573
#
66-
# source_suffix = ['.rst', '.md']
67-
source_suffix = '.rst'
74+
source_suffix = {
75+
'.rst': 'restructuredtext',
76+
'.md': 'markdown',
77+
}
6878

6979
# The master toctree document.
7080
master_doc = 'index'
@@ -86,19 +96,28 @@
8696
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
8797

8898
# The name of the Pygments (syntax highlighting) style to use.
89-
pygments_style = 'sphinx'
99+
#pygments_style = 'sphinx'
100+
pygments_style = 'manni'
90101

91102
# If true, `todo` and `todoList` produce output, else they produce nothing.
92103
todo_include_todos = True
93104

94-
95105
# -- Options for HTML output ----------------------------------------------
96106

97107
# The theme to use for HTML and HTML Help pages. See the documentation for
98108
# a list of builtin themes.
99109
#
110+
#html_theme = 'classic' # still has a version
100111
html_theme = 'sphinx_rtd_theme'
101112

113+
html_sidebars = {
114+
'**': [
115+
'searchfield.html',
116+
'globaltoc.html',
117+
'relations.html',
118+
]
119+
}
120+
102121
# Theme options are theme-specific and customize the look and feel of a theme
103122
# further. For a list of options available for each theme, see the
104123
# documentation.
@@ -115,12 +134,12 @@
115134
#
116135
# This is required for the alabaster theme
117136
# refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
118-
html_sidebars = {
119-
'**': [
120-
'relations.html', # needs 'show_related': True theme option to display
121-
'searchbox.html',
122-
]
123-
}
137+
# html_sidebars = {
138+
# '**': [
139+
# 'relations.html', # needs 'show_related': True theme option to display
140+
# 'searchbox.html',
141+
# ]
142+
# }
124143

125144

126145
# -- Options for HTMLHelp output ------------------------------------------

mypy.ini

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[mypy]
2+
warn_return_any = True
3+
warn_unused_configs = True
4+
5+
[mypy-honcho.manager]
6+
ignore_missing_imports = True

procman/procman.py

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@
77
import logging
88
import sys
99
import warnings
10+
from pathlib import Path
1011
from threading import Timer
1112

1213
from honcho.manager import Manager
1314
from munch import Munch
1415

15-
from .utils import VERSION, get_userscripts, load_config
16+
from . import __version__ as VERSION
17+
from .utils import get_userscripts, load_config
1618

1719
# from logging_tree import printout # debug logger environment
1820

@@ -54,10 +56,11 @@ def show_paths():
5456
print(mod.__doc__)
5557

5658
print("User cfg file:")
57-
_, cfg = mod.load_config()
58-
print(f' {cfg.resolve()}')
59+
ucfg, cfg = mod.load_config()
60+
cfgfile = cfg.resolve() if cfg.exists() else None
61+
print(f' {cfgfile}')
5962
print("User scripts:")
60-
for item in mod.get_userscripts():
63+
for item in mod.get_userscripts(ucfg, cfg):
6164
print(f' {item}')
6265

6366
except (NameError, KeyError, ModuleNotFoundError) as exc:
@@ -91,7 +94,7 @@ def main(argv=None): # pragma: no cover
9194
parser.add_argument(
9295
'-d',
9396
'--dump-config',
94-
help="dump active yaml configuration to stdout",
97+
help="Dump active yaml configuration to stdout",
9598
action='store_true',
9699
dest="dump",
97100
)
@@ -101,7 +104,14 @@ def main(argv=None): # pragma: no cover
101104
type=int,
102105
default='0',
103106
dest="runfor",
104-
help="Runtime STOP timer in seconds - 0 means run until whenever",
107+
help="Runtime STOP timer in seconds - 0 means run forever",
108+
)
109+
parser.add_argument(
110+
'file',
111+
nargs='?',
112+
metavar="FILE",
113+
type=str,
114+
help="Path to user-defined yaml configuration",
105115
)
106116

107117
args = parser.parse_args()
@@ -111,22 +121,30 @@ def main(argv=None): # pragma: no cover
111121
logging.basicConfig(stream=sys.stdout, level=log_level)
112122
# printout() # logging_tree
113123

114-
ucfg, ufile = load_config()
115-
uscripts = get_userscripts(demo_mode=args.demo)
116-
117-
if len(argv) == 1 and not ufile.exists():
118-
parser.print_help()
119-
print('\nNo cfg file found; use the --demo arg or create a cfg file')
120-
sys.exit(1)
121124
if args.show:
122125
show_paths()
123126
sys.exit(0)
124-
if args.dump:
125-
sys.stdout.write(Munch.toYAML(ucfg))
126-
sys.exit(0)
127127
if args.test:
128128
self_test()
129129
sys.exit(0)
130+
infile = args.file
131+
if infile and not Path(infile).exists():
132+
print(f'Input file {infile} not found!')
133+
sys.exit(1)
134+
if infile:
135+
ufile = Path(infile)
136+
ucfg, _ = load_config(ufile=infile)
137+
else:
138+
ucfg, ufile = load_config()
139+
uscripts = get_userscripts(ucfg, ufile, demo_mode=args.demo)
140+
141+
if args.dump:
142+
sys.stdout.write(Munch.toYAML(ucfg))
143+
sys.exit(0)
144+
if len(argv) == 1 and not ufile.exists():
145+
parser.print_help()
146+
print('\nNo cfg file found; use the --demo arg or create a cfg file')
147+
sys.exit(1)
130148

131149
mgr = Manager()
132150
for user_proc in uscripts:

procman/utils.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,46 +6,45 @@
66
import os
77
import sys
88
from pathlib import Path
9+
from typing import List, Tuple
910

1011
from munch import Munch
1112

12-
if sys.version_info < (3, 8):
13-
from importlib_metadata import version
14-
else:
15-
from importlib.metadata import version
16-
1713
if sys.version_info < (3, 10):
18-
import importlib_resources
14+
import importlib_resources # type: ignore[import-not-found]
1915
else:
2016
import importlib.resources as importlib_resources
2117

22-
VERSION = version('procman')
23-
2418

2519
class FileTypeError(Exception):
2620
"""Raise when the file extension is not '.yml' or '.yaml'"""
2721

2822
__module__ = Exception.__module__
2923

3024

31-
def load_config(file_encoding='utf-8', file_extension='.yaml'):
25+
def load_config(
26+
ufile: str = '', file_encoding: str = 'utf-8', file_extension: str = '.yaml'
27+
) -> Tuple[Munch, Path]:
3228
"""
3329
Load yaml configuration file and munchify the data. If ENV path or local
3430
file is not found in current directory, the default cfg will be loaded.
3531
32+
:param ufile: path string for config file
33+
:type ufile: str
3634
:param file_encoding: file encoding of config file
3735
:type file_encoding: str
3836
:param file_extension: file extension with leading separator
3937
:type file_extension: str
40-
:return tuple: Munch cfg obj, Path obj
38+
:return: Munch and Path objects
4139
:raises FileTypeError: if the input file is not yml
4240
"""
4341
proc_cfg = os.getenv('PROCMAN_CFG', default='')
44-
defconfig_file = f'.procman{file_extension}'
42+
defconfig_file = ufile or f'.procman{file_extension}'
4543

4644
cfgfile = Path(proc_cfg) if proc_cfg else Path(defconfig_file)
4745
if not cfgfile.name.lower().endswith(('.yml', '.yaml')):
48-
raise FileTypeError(f"FileTypeError: unknown file extension: {cfgfile.name}")
46+
msg = 'invalid YAML extension: %s' % cfgfile.name
47+
raise (FileTypeError(msg))
4948
if not cfgfile.exists():
5049
cfgobj = load_base_config()
5150
else:
@@ -55,22 +54,23 @@ def load_config(file_encoding='utf-8', file_extension='.yaml'):
5554
return cfgobj, cfgfile.resolve()
5655

5756

58-
def get_userscripts(demo_mode=False, file_encoding='utf-8', file_extension='.yaml'):
57+
def get_userscripts(usr_cfg: Munch, usr_file: Path, demo_mode: bool = False) -> List[str]:
5958
"""
6059
Get user scripts from Munchified user cfg.
6160
6261
:return: list of scripts
6362
"""
64-
uscripts = []
65-
usr_cfg, usr_file = load_config(file_encoding, file_extension)
63+
uscripts: List = []
6664
ucfg = load_base_config() if not usr_file.exists() or demo_mode else usr_cfg
6765
for item in [x for x in ucfg.scripts if x.proc_enable]:
6866
proc_list = [item.proc_label]
6967
if demo_mode:
7068
if getattr(sys, 'frozen', False):
7169
scripts_path = os.path.join(os.path.dirname(sys.executable), 'procman')
7270
else:
73-
scripts_path = importlib_resources.files('procman')
71+
pkg_path = importlib_resources.files('procman')
72+
with importlib_resources.as_file(pkg_path) as path:
73+
scripts_path = str(path)
7474
proc_str = (
7575
f'{item.proc_runner} ' if item.proc_runner else ''
7676
) + f'{os.path.join(scripts_path, item.proc_dir, item.proc_name)}'
@@ -92,7 +92,7 @@ def get_userscripts(demo_mode=False, file_encoding='utf-8', file_extension='.yam
9292
return uscripts
9393

9494

95-
def load_base_config():
95+
def load_base_config() -> Munch:
9696
"""
9797
Load initial procman config with our baseline example values. This is
9898
used to both run the example flask app and provide a user-facing example

pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ log_cli = true
1515
doctest_optionflags = ["ELLIPSIS", "NORMALIZE_WHITESPACE",]
1616
addopts = "--strict-markers"
1717
markers = "subscript"
18+
filterwarnings = ["ignore:currentThread:DeprecationWarning",]
1819

1920
[tool.coverage.run]
2021
branch = true
@@ -31,7 +32,7 @@ omit = [
3132
source = ["procman"]
3233

3334
[tool.coverage.report]
34-
fail_under = 10
35+
fail_under = 70
3536
show_missing = true
3637

3738
[tool.black]

setup.cfg

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ doc =
4949
sphinx
5050
sphinx_git
5151
recommonmark
52-
sphinx_rtd_theme
52+
sphinx_rtd_theme<3.0
5353
sphinxcontrib-apidoc
5454
test =
5555
pytest

tests/test_misc.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,14 @@ def test_load_config_bogus(monkeypatch):
3939
monkeypatch.setenv("PROCMAN_CFG", "testme.txt")
4040
with pytest.raises(FileTypeError) as excinfo:
4141
_, pfile = load_config()
42-
assert 'unknown file extension' in str(excinfo.value)
42+
assert 'invalid YAML extension' in str(excinfo.value)
4343
assert 'testme.txt' in str(excinfo.value)
4444

4545

4646
def test_get_userscripts():
47-
uscripts = get_userscripts(True)
48-
# print(uscripts)
47+
popts, pfile = load_config()
48+
uscripts = get_userscripts(popts, pfile, True)
49+
print(uscripts)
4950

5051
assert isinstance(uscripts, list)
5152
assert len(uscripts) == 2

0 commit comments

Comments
 (0)