Skip to content

Commit 59f7cf9

Browse files
committed
Merge develop into master
Squashed commit of the following: commit 8144ae3 Author: Radu Ghitescu <radu.ghitescu@gmail.com> Date: Sat May 23 14:50:58 2020 +0100 Bump to v0.2.0 commit 59b2308 Author: Radu Ghitescu <radu.ghitescu@gmail.com> Date: Sat May 23 14:49:59 2020 +0100 Update module discovery and console outputs (RaduG#6) * Replace model lookup with recursive os.walk based function which treats modules and packages in a consistent way. Update docstrings to use PEP484-style type information * Streamlined module discovery, unified discovery for packages and modules and tracking grouped by module - simplify module discovery with os.walk - FunctionCallMonitor now stores tracked functions grouped by module - import_module_from_file checks if the module is already imported and returns the module object from sys.modules; this fixes an issue occuring when a function is aliased in another module and the aliased reference is tested when the module in which the original function is defined was imported again after the aliased one - update docstrings with PEP-484 types * Update console output and add tests using pytester - the default output is now in line with pytest-cov - added option --func_cov_report for future extensibility; implemented term-missing which has the same effect as in pytest-cov, but shows the names of the untested functions * Remove unnecessary files * Update sample output and add --func_cov_report information * Make tests a package again * Load pytester * Load pytest_func_cov during tests commit c77ace4 Author: vladg94 <vladg94@users.noreply.github.com> Date: Sun Apr 5 07:55:35 2020 -0700 Add Tests For find_package function (RaduG#5) * Add Tests For find_package function * Add scope to pytest.fixture packag/non_package * Mistake removal# * Modified test for find_package with packages * remove print statements * Add tests for get_functions defined in module. Reformated file with black. * Fix tests Co-authored-by: Radu Ghitescu <radu.ghitescu@gmail.com> commit 00f8065 Author: Radu Ghitescu <radu.ghitescu@gmail.com> Date: Mon Mar 30 10:24:08 2020 +0100 Run Black commit 03c9f90 Author: Radu Ghitescu <radu.ghitescu@gmail.com> Date: Sun Mar 29 15:13:07 2020 +0100 Run Black formatter commit 2695e24 Author: Radu Ghitescu <radu.ghitescu@gmail.com> Date: Sun Mar 29 15:09:34 2020 +0100 Test is_package using temp folders commit bead290 Author: Radu Ghitescu <radu.ghitescu@gmail.com> Date: Sun Mar 29 14:59:25 2020 +0100 Add .vscode commit e978ea7 Author: vladg94 <vladg94@users.noreply.github.com> Date: Wed Mar 18 07:01:35 2020 -0700 Vg test branch (RaduG#4) * Add tests for is_package
1 parent e20902f commit 59f7cf9

File tree

10 files changed

+622
-245
lines changed

10 files changed

+622
-245
lines changed

.github/workflows/build.yml

+1
Original file line numberDiff line numberDiff line change
@@ -36,4 +36,5 @@ jobs:
3636
- name: Test with pytest
3737
run: |
3838
pip install pytest
39+
python setup.py develop
3940
pytest

.gitignore

+4-2
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,8 @@ dmypy.json
128128
# Pyre type checker
129129
.pyre/
130130

131-
132131
# IDE
133-
.idea/
132+
.idea/
133+
134+
# Vscode
135+
.vscode/

README.md

+22-24
Original file line numberDiff line numberDiff line change
@@ -24,33 +24,31 @@ pytest --func_cov=myproject tests/
2424
Produces a report like:
2525

2626
```
27-
Found 10 functions and methods:
28-
- project.functions.calculate_mean
29-
- project.functions.calculate_statistics
30-
- project.functions.calculate_stdev
31-
- project.utilities.utils.some_function
32-
- project.utilities.utils.SomeClass.__init__
33-
- project.utilities.utils.SomeClass.a_eq_b
34-
- project.utilities.utils.SomeClass.a_gt_b
35-
- project.utilities.utils.SomeClass.greeting
36-
- project.utilities.utils.SomeClass.sum
37-
- project.utilities.utils.SomeClass.get_name
27+
--------------------pytest_func_cov-----------
28+
Name Funcs Miss Cover
29+
----------------------------------------------
30+
myproject/module1.py 7 5 28%
31+
myproject/module2.py 10 3 70%
32+
----------------------------------------------
33+
TOTAL 17 8 47%
34+
```
3835

39-
Called 5 functions and methods:
40-
- project.functions.calculate_statistics
41-
- project.utilities.utils.some_function
42-
- project.utilities.utils.SomeClass.__init__
43-
- project.utilities.utils.SomeClass.sum
44-
- project.utilities.utils.SomeClass.get_name
36+
Similar to pytest-cov, you can use the ```--func_cov_report``` argument to configure the output. At the moment, the only
37+
supported option is ```term-missing```, which adds another column to the output which lists all untested functions.
4538

46-
There are 5 functions and methods which were not called during testing:
47-
- project.functions.calculate_mean
48-
- project.functions.calculate_stdev
49-
- project.utilities.utils.SomeClass.a_eq_b
50-
- project.utilities.utils.SomeClass.a_gt_b
51-
- project.utilities.utils.SomeClass.greeting
39+
```bash
40+
pytest --func_cov=myproject --func_cov_report=term-missing tests/
41+
```
42+
Produces a report like:
5243

53-
Total function coverage: 50.0%
44+
```
45+
--------------------pytest_func_cov--------------------
46+
Name Funcs Miss Cover Missing
47+
-------------------------------------------------------
48+
myproject/module1.py 7 5 28% func1, func2, MyClass.method, MyClass.static_method, MyClass.class_method
49+
myproject/module2.py 10 3 70% func3, func4, <lambda>
50+
-------------------------------------------------------
51+
TOTAL 17 8 47%
5452
```
5553

5654
# Configuration

pytest_func_cov/plugin.py

+70-50
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ def pytest_addoption(parser):
2323
nargs="?",
2424
const=True,
2525
)
26+
group.addoption(
27+
"--func_cov_report",
28+
dest="func_cov_report",
29+
action="append",
30+
default=[],
31+
metavar="SOURCE",
32+
nargs="?",
33+
const=True,
34+
)
2635

2736
parser.addini("ignore_func_names", "function names to ignore", "linelist", [])
2837

@@ -36,9 +45,7 @@ def pytest_load_initial_conftests(early_config, parser, args):
3645
class FuncCovPlugin:
3746
def __init__(self, args):
3847
self.args = args
39-
self.indexer = FunctionIndexer(
40-
args.getini("ignore_func_names")
41-
)
48+
self.indexer = FunctionIndexer(args.getini("ignore_func_names"))
4249

4350
def pytest_sessionstart(self, session):
4451
"""
@@ -62,13 +69,13 @@ def pytest_sessionstart(self, session):
6269
pytest_cov_paths = [session.fspath]
6370
else:
6471
pytest_cov_paths = [
65-
os.path.join(session.fspath, path) for path in pytest_cov_paths
72+
os.path.join(session.fspath, path.rstrip("/\\"))
73+
for path in pytest_cov_paths
6674
]
6775

6876
for package_path in pytest_cov_paths:
6977
self.indexer.index_package(package_path)
7078

71-
7279
def pytest_collect_file(self, path):
7380
"""
7481
Pytest hook - called before the collection of a file. At this point
@@ -78,7 +85,7 @@ def pytest_collect_file(self, path):
7885
Args:
7986
path (str): Path to test file
8087
"""
81-
self.indexer.register_source_module(path)
88+
self.indexer.register_source_module(str(path))
8289

8390
def pytest_terminal_summary(self, terminalreporter):
8491
"""
@@ -89,47 +96,60 @@ def pytest_terminal_summary(self, terminalreporter):
8996
Args:
9097
terminalreporter:
9198
"""
92-
functions_found = [
93-
get_full_function_name(f)
94-
for f in self.indexer.monitor.registered_functions
95-
]
96-
functions_called = [
97-
get_full_function_name(f)
98-
for f in self.indexer.monitor.called_functions
99-
]
100-
functions_not_called = [
101-
get_full_function_name(f)
102-
for f in self.indexer.monitor.missed_functions
103-
]
104-
105-
coverage = round((len(functions_called) / len(functions_found)) * 100, 0)
106-
107-
# Write functions found message
108-
terminalreporter.write(
109-
f"Found {len(functions_found)} functions and methods:\n", bold=True
110-
)
111-
terminalreporter.write("\n".join(f"- {f_n}" for f_n in functions_found))
112-
terminalreporter.write("\n\n")
113-
114-
# Write functions tested message
115-
terminalreporter.write(
116-
f"Called {len(functions_called)} functions and methods:\n", bold=True
117-
)
118-
terminalreporter.write(
119-
"\n".join(f"- {f_n}" for f_n in functions_called), green=True
120-
)
121-
terminalreporter.write("\n\n")
122-
123-
# Write functions not tested message
124-
terminalreporter.write(
125-
f"There are {len(functions_not_called)} functions and methods which were not called during testing:\n",
126-
bold=True,
127-
red=True,
128-
)
129-
terminalreporter.write(
130-
"\n".join(f"- {f_n}" for f_n in functions_not_called), red=True
131-
)
132-
terminalreporter.write("\n\n")
133-
134-
# Write test coverage
135-
terminalreporter.write(f"Total function coverage: {coverage}%\n", bold=True)
99+
output_options = self.args.known_args_namespace.func_cov_report
100+
include_missing = "term-missing" in output_options
101+
102+
tr = terminalreporter
103+
cwd = os.getcwd()
104+
105+
found = self.indexer.monitor.registered_functions
106+
called = self.indexer.monitor.called_functions
107+
missed = self.indexer.monitor.missed_functions
108+
109+
module_paths = [sys.modules[m].__file__[len(cwd) + 1 :] for m, _ in found]
110+
max_name_len = max([len(mp) for mp in module_paths] + [5])
111+
112+
fmt_name = "%%- %ds " % max_name_len
113+
header = (fmt_name % "Name") + " Funcs Miss" + "%*s" % (10, "Cover")
114+
115+
if include_missing:
116+
header += "%*s" % (10, "Missing")
117+
118+
fmt_coverage = fmt_name + "%6d %6d" + "%%%ds%%%%" % (9,)
119+
if include_missing:
120+
fmt_coverage += " %s"
121+
122+
msg = "pytest_func_cov"
123+
tr.write("-" * 20 + msg + "-" * 20 + "\n")
124+
tr.write(header + "\n")
125+
tr.write("-" * len(header) + "\n")
126+
127+
total_funcs = 0
128+
total_miss = 0
129+
130+
for i, mp in enumerate(module_paths):
131+
funcs = len(found[i][1])
132+
miss = len(missed[i][1])
133+
cover = int(((funcs - miss) / funcs) * 100)
134+
135+
total_funcs += funcs
136+
total_miss += miss
137+
138+
args = (mp, funcs, miss, cover)
139+
140+
if include_missing:
141+
args += (", ".join([f.__qualname__ for f in missed[i][1]]),)
142+
143+
tr.write(fmt_coverage % args)
144+
tr.write("\n")
145+
146+
tr.write("-" * len(header) + "\n")
147+
148+
total_cover = int(((total_funcs - total_miss) / total_funcs) * 100)
149+
150+
args = ("TOTAL", total_funcs, total_miss, total_cover)
151+
152+
if include_missing:
153+
args += ("",)
154+
155+
tr.write(fmt_coverage % args + "\n")

0 commit comments

Comments
 (0)