Skip to content

Commit

Permalink
Merge pull request #268 from clumio-oss/pyproject.toml
Browse files Browse the repository at this point in the history
Add pyproject.toml and move setup.py logic to setup.cfg.
  • Loading branch information
CleanCut authored May 8, 2023
2 parents f021ba4 + 802cd19 commit 2cd780e
Show file tree
Hide file tree
Showing 25 changed files with 208 additions and 208 deletions.
7 changes: 5 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ jobs:
strategy:
matrix:
os: [macos-latest, ubuntu-latest, windows-latest]
python-version: ["3.8", "3.9", "3.10", "3.11"]
python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11"]
exclude:
- os: ubuntu-latest # Ubuntu-latest can only install 3.7+.
python-version: 3.6
fail-fast: false

steps:
- uses: actions/checkout@v3

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ docs/_build/

# Editor files
tags
.idea

# virtualenvs
venv*
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

- Drop Python 2 support.
- Add Python 3.11 to the CI Action.
- Add setup.cfg and pyproject.toml to support the setup.py deprecation in pip 23.
- Minimum Python version supported is now 3.6.

# Version 3.4.3
#### 20 Sep 2022
Expand Down
2 changes: 1 addition & 1 deletion README-pypi.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Features
- **Descriptive** - Multiple verbosity levels, from just dots to full docstring output.
- **Convenient** - Bash-completion and ZSH-completion of options and test targets.
- **Thorough** - Built-in integration with `coverage`_
- **Modern** - Supports Python 3.5+. Additionally, `PyPy` is supported on a best-effort basis.
- **Modern** - Supports Python 3.6+. Additionally, `PyPy` is supported on a best-effort basis.
- **Portable** - macOS, Linux, and BSDs are fully supported. Windows is supported on a best-effort basis.
- **Living** - This project grows and changes. See the `changelog`_

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ Features
- **Convenient** - Bash-completion and ZSH-completion of options and test targets.
- **Thorough** - Built-in integration with [coverage](http://nedbatchelder.com/code/coverage/).
- **Embedded** - Can be run with a setup command without in-site installation.
- **Modern** - Supports Python 3.5+. Additionally, [PyPy](http://pypy.org) is supported on a best-effort basis.
- **Modern** - Supports Python 3.6+. Additionally, [PyPy](http://pypy.org) is supported on a best-effort basis.
- **Portable** - macOS, Linux, and BSDs are fully supported. Windows is supported on a best-effort basis.
- **Living** - This project grows and changes. See the
[changelog](https://github.com/CleanCut/green/blob/main/CHANGELOG.md)
Expand Down
2 changes: 1 addition & 1 deletion green/cmdline.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ def main(argv=None, testing=False):
except OSError as os_error:
if os_error.errno == 39:
# "Directory not empty" when trying to delete the temp dir can just be a warning
print("warning: {}".format(os_error.strerror))
print(f"warning: {os_error.strerror}")
else:
raise (os_error)
else:
Expand Down
2 changes: 1 addition & 1 deletion green/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def get_user_options():
if len(names) == 1:
names.insert(0, None)
if not action.const:
names[1] += str("=")
names[1] += "="
options.append((names[1], names[0], action.help))

return options
Expand Down
10 changes: 4 additions & 6 deletions green/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import coverage # pragma: no cover

coverage_version = "Coverage {}".format(coverage.__version__) # pragma: no cover
coverage_version = f"Coverage {coverage.__version__}" # pragma: no cover

import copy # pragma: no cover
import logging # pragma: no cover
Expand Down Expand Up @@ -66,7 +66,7 @@
)


class StoreOpt(object): # pragma: no cover
class StoreOpt: # pragma: no cover
"""
Helper class for storing lists of the options themselves to hand out to the
shell completion scripts.
Expand Down Expand Up @@ -420,9 +420,7 @@ def parseArguments(argv=None): # pragma: no cover
)
)

cov_args = parser.add_argument_group(
"Coverage Options ({})".format(coverage_version)
)
cov_args = parser.add_argument_group(f"Coverage Options ({coverage_version})")
store_opt(
cov_args.add_argument(
"-r",
Expand Down Expand Up @@ -563,7 +561,7 @@ def parseArguments(argv=None): # pragma: no cover
return args


class ConfigFile(object): # pragma: no cover
class ConfigFile: # pragma: no cover
"""
Filehandle wrapper that adds a "[green]" section to the start of a config
file so that users don't actually have to manually add a [green] section.
Expand Down
4 changes: 2 additions & 2 deletions green/djangorunner.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def django_missing():

class DjangoRunner(DiscoverRunner):
def __init__(self, verbose=-1, **kwargs):
super(DjangoRunner, self).__init__(**kwargs)
super().__init__(**kwargs)
self.verbose = verbose
self.loader = GreenTestLoader()

Expand All @@ -89,7 +89,7 @@ def add_arguments(cls, parser):
Green 'verbose' level for tests. Value should be an integer
that green supports. For example: --green-verbosity 3""",
)
super(DjangoRunner, cls).add_arguments(parser)
super().add_arguments(parser)

def run_tests(self, test_labels, extra_tests=None, **kwargs):
"""
Expand Down
8 changes: 4 additions & 4 deletions green/junit.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from lxml.etree import Element, SubElement, tostring as to_xml


class JUnitDialect(object):
class JUnitDialect:
"""
Hold the name of the elements defined in the JUnit XML schema (for JUnit 4).
"""
Expand All @@ -23,7 +23,7 @@ class JUnitDialect(object):
TEST_TIME = "time"


class Verdict(object):
class Verdict:
"""
Enumeration of possible test verdicts
"""
Expand All @@ -34,7 +34,7 @@ class Verdict(object):
SKIPPED = 3


class JUnitXML(object):
class JUnitXML:
"""
Serialize a GreenTestResult object into a JUnit XML file, that can
be read by continuous integration servers, for example.
Expand Down Expand Up @@ -79,7 +79,7 @@ def _add_passing_tests(collection, test_results):

@staticmethod
def _suite_name(test):
return "%s.%s" % (test.module, test.class_name)
return f"{test.module}.{test.class_name}"

@staticmethod
def _add_failures(collection, test_results):
Expand Down
50 changes: 20 additions & 30 deletions green/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class GreenTestLoader(unittest.TestLoader):
suiteClass = GreenTestSuite

def loadTestsFromTestCase(self, testCaseClass):
debug("Examining test case {}".format(testCaseClass.__name__), 3)
debug(f"Examining test case {testCaseClass.__name__}", 3)

def filter_test_methods(attrname):
return (
Expand All @@ -33,7 +33,7 @@ def filter_test_methods(attrname):
)

test_case_names = list(filter(filter_test_methods, dir(testCaseClass)))
debug("Test case names: {}".format(test_case_names))
debug(f"Test case names: {test_case_names}")

# Use default unittest.TestSuite sorting method if not overridden
test_case_names.sort(key=functools.cmp_to_key(self.sortTestMethodsUsing))
Expand All @@ -51,7 +51,7 @@ def loadFromModuleFilename(self, filename):
try:
__import__(dotted_module)
loaded_module = sys.modules[dotted_module]
debug("Imported {}".format(dotted_module), 2)
debug(f"Imported {dotted_module}", 2)
except unittest.case.SkipTest as e:
# TODO: #25 - Right now this mimics the behavior in unittest. Lets
# refactor it and simplify it after we make sure it works.
Expand All @@ -63,7 +63,7 @@ def testSkipped(self):
pass # pragma: no cover

TestClass = type(
str("ModuleSkipped"), (unittest.case.TestCase,), {filename: testSkipped}
"ModuleSkipped", (unittest.case.TestCase,), {filename: testSkipped}
)
return self.suiteClass((TestClass(filename),))
except:
Expand All @@ -78,7 +78,7 @@ def testFailure(self):
raise ImportError(message)

TestClass = type(
str("ModuleImportFailure"),
"ModuleImportFailure",
(unittest.case.TestCase,),
{filename: testFailure},
)
Expand All @@ -91,22 +91,12 @@ def testFailure(self):
# --- Find the tests inside the loaded module ---
return self.loadTestsFromModule(loaded_module)

if sys.version_info >= (3, 5): # pragma: no cover

def loadTestsFromModule(self, module, pattern=None):
tests = super(GreenTestLoader, self).loadTestsFromModule(
module, pattern=pattern
)
return flattenTestSuite(tests, module)

else: # pragma: no cover

def loadTestsFromModule(self, module):
tests = super(GreenTestLoader, self).loadTestsFromModule(module)
return flattenTestSuite(tests, module)
def loadTestsFromModule(self, module, pattern=None):
tests = super().loadTestsFromModule(module, pattern=pattern)
return flattenTestSuite(tests, module)

def loadTestsFromName(self, name, module=None):
tests = super(GreenTestLoader, self).loadTestsFromName(name, module)
tests = super().loadTestsFromName(name, module)
return flattenTestSuite(tests, module)

def discover(self, current_path, file_pattern="test*.py", top_level_dir=None):
Expand All @@ -121,7 +111,7 @@ def discover(self, current_path, file_pattern="test*.py", top_level_dir=None):
"""
current_abspath = os.path.abspath(current_path)
if not os.path.isdir(current_abspath):
raise ImportError("'{}' is not a directory".format(str(current_path)))
raise ImportError(f"'{current_path}' is not a directory")
suite = GreenTestSuite()
try:
for file_or_dir_name in sorted(os.listdir(current_abspath)):
Expand Down Expand Up @@ -157,7 +147,7 @@ def discover(self, current_path, file_pattern="test*.py", top_level_dir=None):
if module_suite:
suite.addTest(module_suite)
except OSError:
debug("WARNING: Test discovery failed at path {}".format(current_path))
debug(f"WARNING: Test discovery failed at path {current_path}")

return flattenTestSuite(suite) if suite.countTestCases() else None

Expand All @@ -176,7 +166,7 @@ def loadTargets(self, targets, file_pattern="test*.py"):
for target in targets:
suite = self.loadTarget(target, file_pattern)
if not suite:
debug("Found 0 tests for target '{}'".format(target))
debug(f"Found 0 tests for target '{target}'")
continue
suites.append(suite)
num_tests = suite.countTestCases()
Expand Down Expand Up @@ -229,7 +219,7 @@ def loadTarget(self, target, file_pattern="test*.py"):
continue
tests = self.discover(candidate, file_pattern=file_pattern)
if tests and tests.countTestCases():
debug("Load method: DISCOVER - {}".format(candidate))
debug(f"Load method: DISCOVER - {candidate}")
return flattenTestSuite(tests)

# DOTTED OBJECT - These will discover a specific object if it is
Expand All @@ -244,9 +234,9 @@ def loadTarget(self, target, file_pattern="test*.py"):
del tests._tests[index]

except Exception as e:
raise Exception("Exception while loading {}: {}".format(target, e))
raise Exception(f"Exception while loading {target}: {e}")
if tests and tests.countTestCases():
debug("Load method: DOTTED OBJECT - {}".format(target))
debug(f"Load method: DOTTED OBJECT - {target}")
return flattenTestSuite(tests)

# FILE VARIATIONS - These will import a specific file and any tests
Expand Down Expand Up @@ -289,15 +279,15 @@ def testFailure(self):
raise ImportError(message) # pragma: no cover

TestClass = type(
str("ModuleImportFailure"),
"ModuleImportFailure",
(unittest.case.TestCase,),
{dotted_path: testFailure},
)
return self.suiteClass((TestClass(dotted_path),))
if need_cleanup:
sys.path.remove(cwd)
if tests and tests.countTestCases():
debug("Load method: FILE - {}".format(candidate))
debug(f"Load method: FILE - {candidate}")
return tests

return None
Expand Down Expand Up @@ -345,7 +335,7 @@ def toParallelTargets(suite, targets):
# finest-grained module it belongs to, which simplifies our job.
proto_test_list = toProtoTestList(suite)
# Extract a list of the modules that all of the discovered tests are in
modules = set([x.module for x in proto_test_list])
modules = {x.module for x in proto_test_list}
# Get the list of user-specified targets that are NOT modules
non_module_targets = []
for target in targets:
Expand Down Expand Up @@ -446,13 +436,13 @@ def findDottedModuleAndParentDir(file_path):
would be returned.
"""
if not os.path.isfile(file_path):
raise ValueError("'{}' is not a file.".format(file_path))
raise ValueError(f"'{file_path}' is not a file.")
parent_dir = os.path.dirname(os.path.abspath(file_path))
dotted_module = os.path.basename(file_path).replace(".py", "")
while isPackage(parent_dir):
dotted_module = os.path.basename(parent_dir) + "." + dotted_module
parent_dir = os.path.dirname(parent_dir)
debug("Dotted module: {} -> {}".format(parent_dir, dotted_module), 2)
debug(f"Dotted module: {parent_dir} -> {dotted_module}", 2)
return (dotted_module, parent_dir)


Expand Down
4 changes: 2 additions & 2 deletions green/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def __init__(self, termcolor=None):

def wrap(self, text, style):
if self.termcolor:
return "%s%s%s" % (style, text, Style.RESET_ALL)
return f"{style}{text}{Style.RESET_ALL}"
else:
return text

Expand Down Expand Up @@ -98,7 +98,7 @@ def className(self, text):
return text


class GreenStream(object):
class GreenStream:
"""
Wraps a stream-like object with the following additional features:
Expand Down
12 changes: 4 additions & 8 deletions green/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ def ddebug(msg, err=None): # pragma: no cover
err = "".join(traceback.format_exception(*err))
else:
err = ""
sys.__stdout__.write("({}) {} {}".format(os.getpid(), msg, err) + "\n")
sys.__stdout__.write(f"({os.getpid()}) {msg} {err}\n")
sys.__stdout__.flush()


class ProcessLogger(object):
class ProcessLogger:
"""
I am used by LoggingDaemonlessPool to get crash output out to the logger,
instead of having process crashes be silent
Expand Down Expand Up @@ -94,9 +94,7 @@ def __init__(
):
self._finalizer = finalizer
self._finalargs = finalargs
super(LoggingDaemonlessPool37, self).__init__(
processes, initializer, initargs, maxtasksperchild
)
super().__init__(processes, initializer, initargs, maxtasksperchild)

def _repopulate_pool(self):
"""
Expand Down Expand Up @@ -154,9 +152,7 @@ def __init__(
):
self._finalizer = finalizer
self._finalargs = finalargs
super(LoggingDaemonlessPool38, self).__init__(
processes, initializer, initargs, maxtasksperchild, context
)
super().__init__(processes, initializer, initargs, maxtasksperchild, context)

def _repopulate_pool(self):
return self._repopulate_pool_static(
Expand Down
Loading

0 comments on commit 2cd780e

Please sign in to comment.