From d67c4c59936b38ee17743e6cb46b7ce4f9a5819b Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Fri, 23 Jun 2023 15:32:45 -0400 Subject: [PATCH 1/6] fix pytest badge by renaming file --- .github/workflows/{pytest.yaml => run-pytest.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{pytest.yaml => run-pytest.yml} (100%) diff --git a/.github/workflows/pytest.yaml b/.github/workflows/run-pytest.yml similarity index 100% rename from .github/workflows/pytest.yaml rename to .github/workflows/run-pytest.yml From 2221c891caba8029c81a60eff701d96272367d07 Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Fri, 23 Jun 2023 15:51:58 -0400 Subject: [PATCH 2/6] update readme with proper url --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2059180..ecc3ddb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # logmuse -[![Build Status](https://travis-ci.org/databio/logmuse.svg?branch=master)](https://travis-ci.org/databio/logmuse) +[![Build Status](https://github.com/databio/logmuse/actions/workflows/run-pytest.yml/badge.svg?branch=master)](https://github.com/databio/logmuse/actions/workflows/run-pytest.yml/badge.svg?branch=master) [![Coverage Status](https://coveralls.io/repos/github/vreuter/logmuse/badge.svg?branch=master)](https://coveralls.io/github/vreuter/logmuse?branch=master) Logmuse is a small logging setup package. The point of logmuse is to make it super simple to add CLI-control of logging to your python CLI tool. It just provides a simple interface so that standard arguments can be passed on to the logger. From 04dd262f5497ad89ce9e93c8eb5b4b94381ff74f Mon Sep 17 00:00:00 2001 From: Donald Campbell <125581724+donaldcampbelljr@users.noreply.github.com> Date: Fri, 23 Jun 2023 15:55:37 -0400 Subject: [PATCH 3/6] fix typo master -> dev --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ecc3ddb..7c25722 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # logmuse -[![Build Status](https://github.com/databio/logmuse/actions/workflows/run-pytest.yml/badge.svg?branch=master)](https://github.com/databio/logmuse/actions/workflows/run-pytest.yml/badge.svg?branch=master) +[![Build Status](https://github.com/databio/logmuse/actions/workflows/run-pytest.yml/badge.svg?branch=dev)](https://github.com/databio/logmuse/actions/workflows/run-pytest.yml/badge.svg?branch=dev) [![Coverage Status](https://coveralls.io/repos/github/vreuter/logmuse/badge.svg?branch=master)](https://coveralls.io/github/vreuter/logmuse?branch=master) Logmuse is a small logging setup package. The point of logmuse is to make it super simple to add CLI-control of logging to your python CLI tool. It just provides a simple interface so that standard arguments can be passed on to the logger. From b31ad0fc35c40767be1276c4201e617571c9c625 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 4 Apr 2024 17:21:11 +0200 Subject: [PATCH 4/6] updated python support and lint --- .github/workflows/python-publish.yml | 37 +++++---- .github/workflows/run-pytest.yml | 2 +- docs/changelog.md | 4 + logmuse/_version.py | 2 +- logmuse/est.py | 14 ++-- setup.py | 22 ++--- tests/conftest.py | 2 +- tests/test_add_logging_options.py | 43 ++++++---- tests/test_basic_setup_logger.py | 115 +++++++++++++++++---------- tests/test_logger_via_cli.py | 44 ++++++---- 10 files changed, 175 insertions(+), 110 deletions(-) diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 48c52e1..555ecab 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -1,6 +1,3 @@ -# This workflows will upload a Python Package using Twine when a release is created -# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries - name: Upload Python Package on: @@ -9,22 +6,24 @@ on: jobs: deploy: + runs-on: ubuntu-latest + name: upload release to PyPI + permissions: + id-token: write # IMPORTANT: this permission is mandatory for trusted publishing steps: - - uses: actions/checkout@v2 - - name: Set up Python - uses: actions/setup-python@v2 - with: - python-version: "3.x" - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install setuptools wheel twine - - name: Build and publish - env: - TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} - TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} - run: | - python setup.py sdist bdist_wheel - twine upload dist/* + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install setuptools wheel twine + - name: Build and publish + run: | + python setup.py sdist bdist_wheel + - name: Publish package distributions to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/run-pytest.yml b/.github/workflows/run-pytest.yml index e93c815..90f0ca2 100644 --- a/.github/workflows/run-pytest.yml +++ b/.github/workflows/run-pytest.yml @@ -11,7 +11,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - python-version: [3.9] + python-version: ["3.8", "3.12"] os: [ubuntu-latest] steps: diff --git a/docs/changelog.md b/docs/changelog.md index aa4278b..1dd6f19 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -1,5 +1,9 @@ # Changelog +## [0.2.8] -- 2024-04-04 +### Changed +- Updated Python versions to >3.8 + ## [0.2.7] -- 2021-09-08 ### Changed - Drop support 2to3 for RTD compatibility diff --git a/logmuse/_version.py b/logmuse/_version.py index 6cd38b7..c49a95c 100644 --- a/logmuse/_version.py +++ b/logmuse/_version.py @@ -1 +1 @@ -__version__ = "0.2.7" +__version__ = "0.2.8" diff --git a/logmuse/est.py b/logmuse/est.py index ddcbb66..1f0d382 100644 --- a/logmuse/est.py +++ b/logmuse/est.py @@ -285,10 +285,12 @@ def init_logger( (lambda _: fmt) if fmt else ( - lambda hdlr: BASIC_LOGGING_FORMAT - if plain_format - or not (devmode or fine or isinstance(hdlr, logging.FileHandler)) - else (FULL_DEV_LOGGING_FMT if use_full_names else DEV_LOGGING_FMT) + lambda hdlr: ( + BASIC_LOGGING_FORMAT + if plain_format + or not (devmode or fine or isinstance(hdlr, logging.FileHandler)) + else (FULL_DEV_LOGGING_FMT if use_full_names else DEV_LOGGING_FMT) + ) ) ) @@ -329,7 +331,7 @@ def setup_logger( plain_format=False, style=None, ): - """ Old alias for init_logger for backwards compatibility """ + """Old alias for init_logger for backwards compatibility""" warnings.warn("Please use init_logger in place of setup_logger", DeprecationWarning) return init_logger( name, @@ -386,7 +388,7 @@ def _level_from_verbosity(verbosity): class AbsentOptionException(Exception): - """ Exception subtype suggesting that client should add log options. """ + """Exception subtype suggesting that client should add log options.""" def __init__(self, missing_optname): likely_reason = ( diff --git a/setup.py b/setup.py index 4322ec6..b846093 100644 --- a/setup.py +++ b/setup.py @@ -9,7 +9,7 @@ def read_reqs(reqs_name): deps = [] depsfile = os.path.join(REQDIR, "requirements-{}.txt".format(reqs_name)) - with open(depsfile, 'r') as f: + with open(depsfile, "r") as f: for l in f: if not l.strip(): continue @@ -22,11 +22,11 @@ def read_reqs(reqs_name): extra["install_requires"] = [] -with open(os.path.join(PKG, "_version.py"), 'r') as versionfile: +with open(os.path.join(PKG, "_version.py"), "r") as versionfile: version = versionfile.readline().split()[-1].strip("\"'\n") # Handle the pypi README formatting. -with open('README.md') as f: +with open("README.md") as f: long_description = f.read() setup( @@ -35,22 +35,26 @@ def read_reqs(reqs_name): version=version, description="Logging setup", long_description=long_description, - long_description_content_type='text/markdown', + long_description_content_type="text/markdown", classifiers=[ "Development Status :: 4 - Beta", "License :: OSI Approved :: BSD License", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3.5", - "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 2.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ], keywords="logging, workflow, logger, logs", url="https://github.com/databio/{}/".format(PKG), - author=u"Vince Reuter, Nathan Sheffield", + author="Vince Reuter, Nathan Sheffield", license="BSD-2-Clause", scripts=None, include_package_data=True, test_suite="tests", tests_require=read_reqs("dev"), - setup_requires=(["pytest-runner"] if {"test", "pytest", "ptr"} & set(sys.argv) else []), + setup_requires=( + ["pytest-runner"] if {"test", "pytest", "ptr"} & set(sys.argv) else [] + ), **extra ) diff --git a/tests/conftest.py b/tests/conftest.py index 42fc89e..c1668ec 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -9,5 +9,5 @@ @pytest.fixture def parser(): - """ Clean/fresh, blank-slate argument parser instance for a test case """ + """Clean/fresh, blank-slate argument parser instance for a test case""" return argparse.ArgumentParser() diff --git a/tests/test_add_logging_options.py b/tests/test_add_logging_options.py index bc4d759..3e76742 100644 --- a/tests/test_add_logging_options.py +++ b/tests/test_add_logging_options.py @@ -12,28 +12,33 @@ def pytest_generate_tests(metafunc): - """ Generation and parameterization of tests in this module. """ + """Generation and parameterization of tests in this module.""" if "opt" in metafunc.fixturenames: - metafunc.parametrize("opt", list(["--" + x for x in LOGGING_CLI_OPTDATA.keys()])) + metafunc.parametrize( + "opt", list(["--" + x for x in LOGGING_CLI_OPTDATA.keys()]) + ) def test_all_options_are_added(parser, opt): - """ If requested, all of the standard logging options are added. """ + """If requested, all of the standard logging options are added.""" assert opt not in _get_optnames(parser) add_logging_options(parser) assert opt in _get_optnames(parser) def test_each_option_gis_functional(parser, opt): - """ Each added CLI opt can be used as expected. """ + """Each added CLI opt can be used as expected.""" add_logging_options(parser) for a in parser._actions: if opt in a.option_strings: use = get_act_use(parser, a) break else: - pytest.fail("Parser lacks action with name: {}; available: {}". - format(opt, _get_optnames(parser))) + pytest.fail( + "Parser lacks action with name: {}; available: {}".format( + opt, _get_optnames(parser) + ) + ) try: parser.parse_args(use) except Exception as e: @@ -64,21 +69,29 @@ def _build_action_usage(act_kind): given a CLI action will create the representative command line chunks """ from logmuse.est import _VERBOSITY_CHOICES, VERBOSITY_OPTNAME + def get_general_use(act): name = _get_opt_first_name(act) - arg = random.choice(_VERBOSITY_CHOICES) \ - if name == "--" + VERBOSITY_OPTNAME else _random_chars_option() + arg = ( + random.choice(_VERBOSITY_CHOICES) + if name == "--" + VERBOSITY_OPTNAME + else _random_chars_option() + ) return [name, arg] + strategies = [ - ((argparse._StoreTrueAction, argparse._StoreFalseAction), - lambda a: [a.option_strings[0]]), - ((argparse._StoreAction), get_general_use) + ( + (argparse._StoreTrueAction, argparse._StoreFalseAction), + lambda a: [a.option_strings[0]], + ), + ((argparse._StoreAction), get_general_use), ] for kinds, strat in strategies: if issubclass(act_kind, kinds): return strat - raise ValueError("No usage strategies for given kind of option: {}". - format(act_kind)) + raise ValueError( + "No usage strategies for given kind of option: {}".format(act_kind) + ) def _get_optnames(p): @@ -93,11 +106,11 @@ def _get_optnames(p): def _random_chars_option(): - """ Randomly generate arbitrary text value for use as CLI opt argument. """ + """Randomly generate arbitrary text value for use as CLI opt argument.""" pool = string.ascii_letters + string.digits return "".join(random.choice(pool) for _ in range(10)) def _get_opt_first_name(a): - """ Get the first of an action's option names. """ + """Get the first of an action's option names.""" return a.option_strings[0] diff --git a/tests/test_basic_setup_logger.py b/tests/test_basic_setup_logger.py index 35a8ff7..3738c86 100644 --- a/tests/test_basic_setup_logger.py +++ b/tests/test_basic_setup_logger.py @@ -14,20 +14,31 @@ def _random_filename(): - """ Generate random extensionless filename. """ + """Generate random extensionless filename.""" return "".join(random.choice(string.ascii_letters) for _ in range(20)) @pytest.mark.parametrize( ["attr", "check"], - [("level", (getattr(logging, LOGGING_LEVEL) if - isinstance(LOGGING_LEVEL, str) else LOGGING_LEVEL, - "Wrong logging level; expected {} but got {}")), - ("name", (PACKAGE_NAME, "Wrong logger name; expected {} but got {}")), - ("handlers", (1, "Wrong number of handlers; expected {} but got {}", len)), - ("handlers", lambda h: _check_handler(h, loc=DEFAULT_STREAM))]) + [ + ( + "level", + ( + ( + getattr(logging, LOGGING_LEVEL) + if isinstance(LOGGING_LEVEL, str) + else LOGGING_LEVEL + ), + "Wrong logging level; expected {} but got {}", + ), + ), + ("name", (PACKAGE_NAME, "Wrong logger name; expected {} but got {}")), + ("handlers", (1, "Wrong number of handlers; expected {} but got {}", len)), + ("handlers", lambda h: _check_handler(h, loc=DEFAULT_STREAM)), + ], +) def test_all_defaults(attr, check): - """ Check the values on the logger that result from all default arguments. """ + """Check the values on the logger that result from all default arguments.""" logger = init_logger() if hasattr(check, "__call__"): fails = list(itertools.chain(*[check(obj) for obj in getattr(logger, attr)])) @@ -47,23 +58,25 @@ def test_all_defaults(attr, check): @pytest.mark.parametrize( ["att", "val"], - [("name", n) for n in ["arbitrary", "random"]] + - [("level", x) for x in range(0, 50, 10)]) + [("name", n) for n in ["arbitrary", "random"]] + + [("level", x) for x in range(0, 50, 10)], +) def test_single_attr(att, val): - """ Test successful setting of a simple, particular logger attribute. """ + """Test successful setting of a simple, particular logger attribute.""" assert val == getattr(init_logger(**{att: val}), att) def test_make_non_root_name_root(): - """ Non-root name for root logger is prohibited. """ + """Non-root name for root logger is prohibited.""" with pytest.raises(ValueError): init_logger("root", make_root=False) -@pytest.mark.parametrize(["make_root", "exp"], - [(None, PACKAGE_NAME), (False, PACKAGE_NAME), (True, "root")]) +@pytest.mark.parametrize( + ["make_root", "exp"], [(None, PACKAGE_NAME), (False, PACKAGE_NAME), (True, "root")] +) def test_make_root(make_root, exp): - """ Root status for logger has a couple of implications. """ + """Root status for logger has a couple of implications.""" log = init_logger(make_root=make_root) assert exp == log.name assert log.propagate is False @@ -71,23 +84,33 @@ def test_make_root(make_root, exp): @pytest.mark.parametrize( ["kwargs", "exp"], - [({}, False), ({"make_root": False}, False), ({"propagate": False}, False), - ({"propagate": True}, True), ({"make_root": True}, False), - ({"make_root": False, "propagate": False}, False), - ({"make_root": False, "propagate": True}, True), - ({"make_root": True, "propagate": False}, False), - ({"make_root": True, "propagate": True}, True)]) + [ + ({}, False), + ({"make_root": False}, False), + ({"propagate": False}, False), + ({"propagate": True}, True), + ({"make_root": True}, False), + ({"make_root": False, "propagate": False}, False), + ({"make_root": False, "propagate": True}, True), + ({"make_root": True, "propagate": False}, False), + ({"make_root": True, "propagate": True}, True), + ], +) def test_propagate(kwargs, exp): - """ Determination of propagation flag considers root status and propagation. """ + """Determination of propagation flag considers root status and propagation.""" assert init_logger(**kwargs).propagate is exp @pytest.mark.parametrize( ["stream", "exp"], - [(sys.stdout, sys.stdout), (sys.stderr, sys.stderr), - ("not_a_real_stream", DEFAULT_STREAM)]) + [ + (sys.stdout, sys.stdout), + (sys.stderr, sys.stderr), + ("not_a_real_stream", DEFAULT_STREAM), + ], +) def test_stream(stream, exp): - """ Validate stream handler setting for created logger. """ + """Validate stream handler setting for created logger.""" log = init_logger(stream=stream) assert 1 == len(log.handlers) h = _check_hdlr_kind(log, logging.StreamHandler) @@ -96,7 +119,7 @@ def test_stream(stream, exp): @pytest.mark.parametrize("filename", [_random_filename() for _ in range(2)]) def test_logfile(tmpdir, filename): - """ Validate file handler setting for created logger. """ + """Validate file handler setting for created logger.""" fp = tmpdir.join(filename).strpath log = init_logger(logfile=fp) assert 1 == len(log.handlers) @@ -107,7 +130,7 @@ def test_logfile(tmpdir, filename): @pytest.mark.parametrize("filename", [_random_filename() for _ in range(2)]) @pytest.mark.parametrize("stream", [sys.stdout, sys.stderr]) def test_logfile_and_stream(filename, stream, tmpdir): - """ Logging can be both stream and file. """ + """Logging can be both stream and file.""" fp = tmpdir.join(filename).strpath log = init_logger(logfile=fp, stream=stream) assert 2 == len(log.handlers) @@ -131,11 +154,12 @@ def _check_handler(h, lev=None, loc=None): if isinstance(lev, str): lev = getattr(logging, lev) elif not isinstance(lev, int): - raise TypeError("Expected logging level is neither string nor int: " - "{} ({})".format(lev, type(lev))) + raise TypeError( + "Expected logging level is neither string nor int: " + "{} ({})".format(lev, type(lev)) + ) if h.level != lev: - fails.append( - "Wrong level (expected {} but got {})".format(lev, h.level)) + fails.append("Wrong level (expected {} but got {})".format(lev, h.level)) if loc is not None: if loc in [sys.stderr, sys.stdout]: exp_type = logging.StreamHandler @@ -143,11 +167,12 @@ def _check_handler(h, lev=None, loc=None): exp_name = loc.name obs_name = h.stream.name if not isinstance(h, logging.StreamHandler): - fails.append("Expected a stream handler but found {}". - format(type(h))) + fails.append("Expected a stream handler but found {}".format(type(h))) elif h.stream != loc: - fails.append("Unexpected handler location; expected {} but " - "found {}".format(loc.name, h.stream.name)) + fails.append( + "Unexpected handler location; expected {} but " + "found {}".format(loc.name, h.stream.name) + ) elif isinstance(loc, str): exp_type = logging.FileHandler obs_loc = h.stream.name @@ -156,20 +181,26 @@ def _check_handler(h, lev=None, loc=None): else: raise TypeError( "Handler location to check is neither standard stream nor " - "filepath: {} ({})".format(loc, type(loc))) + "filepath: {} ({})".format(loc, type(loc)) + ) if not isinstance(h, exp_type): fails.append("Expected a file handler but found {}".format(type(h))) if loc != obs_loc: - fails.append("Unexpected handler location; expected {} but found {}". - format(exp_name, obs_name)) + fails.append( + "Unexpected handler location; expected {} but found {}".format( + exp_name, obs_name + ) + ) return fails def _check_hdlr_kind(l, k, omit=None): use1 = lambda hdlr: isinstance(hdlr, k) - use2 = (lambda _: True) if omit is None else \ - (lambda hdlr: not isinstance(hdlr, omit)) + use2 = ( + (lambda _: True) if omit is None else (lambda hdlr: not isinstance(hdlr, omit)) + ) hs = [h for h in l.handlers if use1(h) and use2(h)] - assert 1 == len(hs), "Expected exactly 1 handler of type {} but " \ - "found {}".format(k, len(hs)) + assert 1 == len(hs), "Expected exactly 1 handler of type {} but " "found {}".format( + k, len(hs) + ) return hs[0] diff --git a/tests/test_logger_via_cli.py b/tests/test_logger_via_cli.py index d0924d9..c65d89f 100644 --- a/tests/test_logger_via_cli.py +++ b/tests/test_logger_via_cli.py @@ -6,9 +6,15 @@ from hypothesis import given, strategies as st import pytest from logmuse import add_logging_options, logger_via_cli -from logmuse.est import AbsentOptionException, LEVEL_BY_VERBOSITY, \ - LOGGING_CLI_OPTDATA, SILENCE_LOGS_OPTNAME, VERBOSITY_OPTNAME, \ - _MIN_VERBOSITY, _MAX_VERBOSITY +from logmuse.est import ( + AbsentOptionException, + LEVEL_BY_VERBOSITY, + LOGGING_CLI_OPTDATA, + SILENCE_LOGS_OPTNAME, + VERBOSITY_OPTNAME, + _MIN_VERBOSITY, + _MAX_VERBOSITY, +) __author__ = "Vince Reuter" @@ -17,22 +23,25 @@ VERBOSITY_OPTNAME = "--" + VERBOSITY_OPTNAME + @pytest.fixture def parser(): - """ Update empty argument parser with standard logging options. """ + """Update empty argument parser with standard logging options.""" return add_logging_options(argparse.ArgumentParser()) @pytest.mark.parametrize("missing", list(LOGGING_CLI_OPTDATA.keys())) @pytest.mark.parametrize("strict", [False, True]) def test_opts_not_added(parser, missing, strict): - """ Special exception occurs when it appears that log opts are absent. """ + """Special exception occurs when it appears that log opts are absent.""" opts = parser.parse_args([]) assert all(hasattr(opts, _rawopt(n)) for n in LOGGING_CLI_OPTDATA) delattr(opts, _rawopt(missing)) assert not hasattr(opts, _rawopt(missing)) + def create_logger(): return logger_via_cli(opts, strict=strict) + if strict: with pytest.raises(AbsentOptionException): create_logger() @@ -41,13 +50,13 @@ def create_logger(): def test_repeat_parser_configuration_is_exceptional(parser): - """ add_logging_options must be called just once. """ + """add_logging_options must be called just once.""" with pytest.raises(argparse.ArgumentError): - add_logging_options(parser) # Parser already has the logging options. + add_logging_options(parser) # Parser already has the logging options. def test_opts_added_none_used(parser): - """ Addition of logging options allows logger_via_cli to complete. """ + """Addition of logging options allows logger_via_cli to complete.""" opts = parser.parse_args([]) assert all(hasattr(opts, _rawopt(n)) for n in LOGGING_CLI_OPTDATA) logger = logger_via_cli(opts) @@ -56,10 +65,13 @@ def test_opts_added_none_used(parser): @pytest.mark.parametrize( ["cmdl", "flag", "hdlr_type"], - [(["--" + SILENCE_LOGS_OPTNAME], True, logging.NullHandler), - ([], False, logging.StreamHandler)]) + [ + (["--" + SILENCE_LOGS_OPTNAME], True, logging.NullHandler), + ([], False, logging.StreamHandler), + ], +) def test_silence(parser, cmdl, flag, hdlr_type): - """ Log silencing generates a null handler. """ + """Log silencing generates a null handler.""" opts = parser.parse_args(cmdl) assert getattr(opts, SILENCE_LOGS_OPTNAME.lstrip("-")) is flag logger = logger_via_cli(opts) @@ -70,7 +82,7 @@ def test_silence(parser, cmdl, flag, hdlr_type): @pytest.mark.parametrize("verbosity", range(_MIN_VERBOSITY, _MAX_VERBOSITY + 1)) def test_typical_verbosity(parser, verbosity): - """ Typical verbosity specifications yield logger with expected level. """ + """Typical verbosity specifications yield logger with expected level.""" opts = parser.parse_args([VERBOSITY_OPTNAME, str(verbosity)]) logger = logger_via_cli(opts) exp = getattr(logging, LEVEL_BY_VERBOSITY[verbosity - 1]) @@ -79,21 +91,21 @@ def test_typical_verbosity(parser, verbosity): @given(verbosity=st.integers(-sys.maxsize, -1)) def test_negative_verbosity(parser, verbosity): - """ Verbosity is pulled up to min logging level. """ + """Verbosity is pulled up to min logging level.""" with pytest.raises(SystemExit): parser.parse_args([VERBOSITY_OPTNAME, str(verbosity)]) @given(verbosity=st.integers(len(LEVEL_BY_VERBOSITY) + 1, sys.maxsize)) def test_excess_verbosity(parser, verbosity): - """ Verbosity saturates / maxes out. """ + """Verbosity saturates / maxes out.""" with pytest.raises(SystemExit): parser.parse_args([VERBOSITY_OPTNAME, str(verbosity)]) @pytest.mark.parametrize("verbosity", ["a", "NOTALEVEL", 2.5]) def test_invalid_verbosity_is_exceptional(parser, verbosity): - """ Verbosity must be a valid level name or an integer. """ + """Verbosity must be a valid level name or an integer.""" with pytest.raises(SystemExit): parser.parse_args([VERBOSITY_OPTNAME, str(verbosity)]) @@ -110,5 +122,5 @@ def _assert_level(log, lev): def _rawopt(n): - """ Reduce option name. """ + """Reduce option name.""" return n.lstrip("--").lstrip("-") From 0549e3c868f93924e59f7535b6397deefa5d82a3 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 4 Apr 2024 17:36:29 +0200 Subject: [PATCH 5/6] updated requirements for python 3.12 --- requirements/requirements-all.txt | 1 + setup.py | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 requirements/requirements-all.txt diff --git a/requirements/requirements-all.txt b/requirements/requirements-all.txt new file mode 100644 index 0000000..8b6d003 --- /dev/null +++ b/requirements/requirements-all.txt @@ -0,0 +1 @@ +setuptools \ No newline at end of file diff --git a/setup.py b/setup.py index b846093..120a95d 100644 --- a/setup.py +++ b/setup.py @@ -20,7 +20,15 @@ def read_reqs(reqs_name): # Additional keyword arguments for setup(). extra = {} -extra["install_requires"] = [] +DEPENDENCIES = [] +with open("requirements/requirements-all.txt", "r") as reqs_file: + for line in reqs_file: + if not line.strip(): + continue + DEPENDENCIES.append(line) + +extra["install_requires"] = DEPENDENCIES + with open(os.path.join(PKG, "_version.py"), "r") as versionfile: version = versionfile.readline().split()[-1].strip("\"'\n") From 4fae3bd32b30d53c145bdd4580b5680138fea8d3 Mon Sep 17 00:00:00 2001 From: Khoroshevskyi Date: Thu, 4 Apr 2024 17:39:34 +0200 Subject: [PATCH 6/6] added lint checker --- .github/workflows/black.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/black.yml diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml new file mode 100644 index 0000000..63e1851 --- /dev/null +++ b/.github/workflows/black.yml @@ -0,0 +1,11 @@ +name: Lint + +on: [push, pull_request] + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + - uses: psf/black@20.8b1