Skip to content

Commit

Permalink
Merge pull request #5 from ramonhagenaars/release/1.2.0
Browse files Browse the repository at this point in the history
Release/1.2.0
  • Loading branch information
ramonhagenaars authored Sep 20, 2020
2 parents 5c289d0 + aef7979 commit 24a8ee7
Show file tree
Hide file tree
Showing 11 changed files with 178 additions and 58 deletions.
6 changes: 5 additions & 1 deletion .coveragerc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
[run]
omit =
setup.py
SConstruct.py
*/docs/*
*/test_resources/*
tests/*
test_resources/*
include =
barentsz/*
43 changes: 23 additions & 20 deletions .github/workflows/pythonapp.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
name: barentsz

on: [push]
on: [push, pull_request]

jobs:
build:
Expand All @@ -24,17 +24,32 @@ jobs:
pip install .[test]
- name: Test
run: |
python setup.py test
run: scons test

- name: Doctest
if: ${{ matrix.python-version == '3.8' && matrix.os == 'ubuntu-latest' }}
run: |
python -m doctest README.md
run: scons doctest

- name: Pycodestyle
run: scons pycodestyle

- name: Pylint
run: scons pylint

- name: Imports
run: scons check format

- name: Mypy
run: scons mypy

- name: Code Complexity
run: scons complexity

- name: Coverage
run: scons coverage

- name: Generate coverage report
run: |
pytest --cov=./ --cov-report=xml
run: pytest --cov=./ --cov-report=xml

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v1
Expand All @@ -46,15 +61,3 @@ jobs:
env_vars: OS,PYTHON
name: codecov-umbrella
fail_ci_if_error: true

- name: Pycodestyle
run: |
pycodestyle barentsz -v
- name: Pylint
run: |
pylint --rcfile=setup.cfg barentsz
- name: Mypy
run: |
mypy barentsz --disallow-untyped-defs
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
[![Python versions](https://img.shields.io/pypi/pyversions/barentsz.svg)](https://img.shields.io/pypi/pyversions/barentsz.svg)
[![PyPI version](https://badge.fury.io/py/barentsz.svg)](https://badge.fury.io/py/barentsz)
![barentsz](https://github.com/ramonhagenaars/barentsz/workflows/barentsz/badge.svg)
[![codecov](https://codecov.io/gh/ramonhagenaars/barentsz/branch/master/graph/badge.svg)](https://codecov.io/gh/ramonhagenaars/barentsz)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/ramonhagenaars/barentsz/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/ramonhagenaars/barentsz/?branch=master)

Expand Down Expand Up @@ -102,7 +101,7 @@ discover(source: Any = None, *, what: Any = typing.List[type], **kwargs: dict) -
>>> help(discover_classes)
Help on function discover_classes in module barentsz._discover:
<BLANKLINE>
discover_classes(source: Union[pathlib.Path, str, module, Iterable[module]], signature: type = typing.Any, include_privates: bool = False, in_private_modules: bool = False, raise_on_fail: bool = False, exclude: Union[Iterable[type], type] = None) -> List[type]
discover_classes(source: Union[pathlib.Path, str, module, Iterable[module]], signature: type = typing.Any, include_privates: bool = False, in_private_modules: bool = False, raise_on_fail: bool = False, exclude: Union[type, Callable[[type], bool], Iterable[Union[type, Callable[[type], bool]]]] = None) -> List[type]
Discover any classes within the given source and according to the given
constraints.
<BLANKLINE>
Expand All @@ -113,13 +112,12 @@ discover_classes(source: Union[pathlib.Path, str, module, Iterable[module]], sig
in_private_modules: if True, private modules are explored as well.
raise_on_fail: if True, raises an ImportError upon the first import
failure.
exclude: a type or multiple types that are to be excluded from the
result.
exclude: one or more types or predicates that are to be excluded
from the result.
<BLANKLINE>
Returns: a list of all discovered classes (types).
<BLANKLINE>


```

### Discover Functions
Expand Down Expand Up @@ -366,6 +364,9 @@ discover_paths(directory: Union[pathlib.Path, str], pattern: str) -> List[pathli

## ❄ Changelist

### 1.2.0 [2020-09-20]
* Changed `exclude` parameter to also allow predicates.

### 1.1.0 [2020-08-05]
* Added the `here` function that returns the directory of the caller of that function.
* Added the `discovery` function that can conveniently find types using the current dir and a given class.
Expand Down
69 changes: 69 additions & 0 deletions SConstruct.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import subprocess

_CHECK_ONLY = 'check' in COMMAND_LINE_TARGETS
_CONTINUE = 'continue' in COMMAND_LINE_TARGETS
_SUBJECT = 'barentsz'


def _exec(cmd: str) -> None:
print(f'>>> {cmd}')
exit_code = subprocess.call(cmd, shell=True)
if exit_code != 0 and not _CONTINUE:
print(f'Exiting with {exit_code}')
Exit(exit_code)


# COMBINATIONS:

if 'all' in COMMAND_LINE_TARGETS:
COMMAND_LINE_TARGETS += ['format', 'quality']

if 'quality' in COMMAND_LINE_TARGETS:
COMMAND_LINE_TARGETS += ['test', 'doctest', 'coverage', 'pycodestyle', 'pylint', 'mypy', 'complexity']

if 'format' in COMMAND_LINE_TARGETS:
COMMAND_LINE_TARGETS += ['autoflake', 'isort']


# QUALITY:

if 'test' in COMMAND_LINE_TARGETS:
_exec('python -m unittest discover tests')

if 'doctest' in COMMAND_LINE_TARGETS:
_exec('python -m doctest README.md')

if 'coverage' in COMMAND_LINE_TARGETS:
_exec('coverage run -m unittest discover tests')
_exec('coverage report -m --fail-under=100')

if 'pycodestyle' in COMMAND_LINE_TARGETS:
_exec(f'pycodestyle {_SUBJECT} -v --config=setup.cfg')

if 'pylint' in COMMAND_LINE_TARGETS:
_exec(f'pylint --rcfile=setup.cfg {_SUBJECT}')

if 'mypy' in COMMAND_LINE_TARGETS:
_exec(f'mypy {_SUBJECT} --show-error-codes --disallow-untyped-defs')

if 'complexity' in COMMAND_LINE_TARGETS:
_exec(f'radon cc {_SUBJECT}')
_exec(f'radon cc {_SUBJECT} -nc --total-average')
_exec(f'xenon {_SUBJECT} --max-absolute B --max-modules A --max-average A')


# FORMAT:

if 'autoflake' in COMMAND_LINE_TARGETS:
cmd = f'autoflake {_SUBJECT}/_here.py --recursive --in-place --remove-unused-variables --expand-star-imports'
if _CHECK_ONLY:
cmd += ' --check'
_exec(cmd)

if 'isort' in COMMAND_LINE_TARGETS:
cmd = f'isort {_SUBJECT} --recursive --quiet'
if _CHECK_ONLY:
cmd += ' --check'
_exec(cmd)

Exit(0)
18 changes: 7 additions & 11 deletions barentsz/__init__.py
Original file line number Diff line number Diff line change
@@ -1,16 +1,12 @@
from barentsz._discover import (
discover,
discover_paths,
discover_packages,
discover_module_names,
discover_modules,
discover_attributes,
discover_classes,
discover_functions,
discover_attributes,
)
from barentsz._here import (
here,
)
from barentsz._meta import (
__version__,
discover_module_names,
discover_modules,
discover_packages,
discover_paths,
)
from barentsz._here import here
from barentsz._meta import __version__
49 changes: 32 additions & 17 deletions barentsz/_discover.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,37 @@
import glob
import inspect
import re
import sys
from importlib import import_module
from inspect import (
getmembers,
isclass,
isfunction,
ismethod,
)
from pathlib import Path
from typing import (
Union,
Dict,
List,
Any,
Callable,
Type,
Dict,
Iterable,
List,
Optional,
Tuple,
Set,
Tuple,
Type,
TypeVar,
Union,
)

from typish import Module, subclass_of, instance_of
from typish import (
Module,
instance_of,
subclass_of,
)

from barentsz._here import here
from barentsz._attribute import Attribute
from barentsz._here import here
from barentsz._typings import ClsPredicate


def discover(
Expand Down Expand Up @@ -150,7 +160,7 @@ def discover_modules(
result.append(imported_module)
except Exception as err:
if raise_on_fail:
raise ImportError(err)
raise ImportError(err) from err
result.sort(key=lambda module: module.__name__)
return result

Expand All @@ -161,7 +171,8 @@ def discover_classes(
include_privates: bool = False,
in_private_modules: bool = False,
raise_on_fail: bool = False,
exclude: Union[Iterable[type], type] = None
exclude: Union[type, ClsPredicate,
Iterable[Union[type, ClsPredicate]]] = None
) -> List[type]:
"""
Discover any classes within the given source and according to the given
Expand All @@ -174,18 +185,22 @@ def discover_classes(
in_private_modules: if True, private modules are explored as well.
raise_on_fail: if True, raises an ImportError upon the first import
failure.
exclude: a type or multiple types that are to be excluded from the
result.
exclude: one or more types or predicates that are to be excluded
from the result.
Returns: a list of all discovered classes (types).
"""
exclude_ = _ensure_set(exclude)
elements = _discover_elements(source, inspect.isclass, include_privates,
elements = _discover_elements(source, isclass, include_privates,
in_private_modules, raise_on_fail)
result = list({cls for cls in elements
if (signature is Any or subclass_of(cls, signature))
and cls not in exclude_})

exclude_predicates = (e for e in exclude_ if isfunction(e))
for pred in exclude_predicates:
result = [cls for cls in result if not pred(cls)] # type: ignore[operator] # noqa
result.sort(key=lambda cls: cls.__name__)
return result

Expand Down Expand Up @@ -214,11 +229,11 @@ def discover_functions(
"""

def filter_(*args_: Iterable[Any]) -> bool:
return (inspect.isfunction(*args_)
or inspect.ismethod(*args_))
return (isfunction(*args_)
or ismethod(*args_))

if not isinstance(source, type):
filter_ = inspect.isfunction # type: ignore
filter_ = isfunction # type: ignore

elements = _discover_elements(source, filter_, include_privates,
in_private_modules, raise_on_fail)
Expand Down Expand Up @@ -321,7 +336,7 @@ def _discover_elements(
raise_on_fail)

elements = [elem for src in sources
for _, elem in inspect.getmembers(src, filter_)
for _, elem in getmembers(src, filter_)
if (in_private_modules or not src.__name__.startswith('_'))
and (include_privates or not elem.__name__.startswith('_'))]
return elements
Expand Down
2 changes: 1 addition & 1 deletion barentsz/_meta.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
__title__ = 'barentsz'
__version__ = '1.1.0'
__version__ = '1.2.0'
__author__ = 'Ramon Hagenaars'
__author_email__ = '[email protected]'
__description__ = 'For discovering modules, classes, functions and attributes.'
Expand Down
3 changes: 3 additions & 0 deletions barentsz/_typings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from typing import Callable

ClsPredicate = Callable[[type], bool]
8 changes: 7 additions & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,10 @@ disable =
too-many-arguments,
missing-module-docstring,
no-value-for-parameter,
isinstance-second-argument-not-valid-type
isinstance-second-argument-not-valid-type,

[isort]
multi_line_output = 3
include_trailing_comma = True
force_grid_wrap = 3
use_parentheses = True
9 changes: 8 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,21 @@

requirements = [
'typish>=1.7.0',
],
]

test_requirements = [
'scons',
'pycodestyle',
'pylint',
'mypy',
'pytest',
'pytest-cov',
'coverage',
'radon',
'xenon',
'autoflake',
'isort',

]

extras = {
Expand Down
Loading

0 comments on commit 24a8ee7

Please sign in to comment.