pytest-inline-tdd 1.2.4__tar.gz → 1.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/.github/workflows/python-publish.yml +5 -1
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/PKG-INFO +2 -2
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/README.md +1 -1
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/c.py +7 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/d.py +3 -3
- pytest_inline_tdd-1.2.7/integration-tests/tdd/e.py +6 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/__about__.py +2 -2
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/plugin.py +84 -2
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/.github/workflows/python-test.yml +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/.gitignore +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/LICENSE +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/changelog +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/convert_tests.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/convert_to_tdd.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/README.md +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/example.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/features.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/a.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/b.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/c.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/d.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo_tdd.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/a.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/a.py.backup +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/b.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/c.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/d.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/e.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/f.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/g.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/h.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/i.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/j.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/time-parallel-tests.sh +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/a.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/a1.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/b.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/d.bak +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/db.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/np_ops.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/prepare-conda-env.sh +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/pyproject.toml +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/__init__.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/ast_future.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/inline.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/strip.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tdd_summary.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/test_tdd.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/test_tdd_verification.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tests/__init__.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tests/test_plugin.py +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tests/test_plugin.py.bak +0 -0
- {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tox.ini +0 -0
|
@@ -30,7 +30,11 @@ jobs:
|
|
|
30
30
|
python -m pip install --upgrade pip
|
|
31
31
|
pip install build
|
|
32
32
|
- name: Build package
|
|
33
|
-
|
|
33
|
+
env:
|
|
34
|
+
SETUPTOOLS_SCM_PRETEND_VERSION: ${{ github.event.release.tag_name }}
|
|
35
|
+
run: |
|
|
36
|
+
export SETUPTOOLS_SCM_PRETEND_VERSION="${SETUPTOOLS_SCM_PRETEND_VERSION#v}"
|
|
37
|
+
python -m build
|
|
34
38
|
- name: Publish package
|
|
35
39
|
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29
|
|
36
40
|
with:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pytest-inline-tdd
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.7
|
|
4
4
|
Summary: A pytest plugin for writing inline tests
|
|
5
5
|
Project-URL: Issues, https://github.com/zzctmac/inline-tdd/issues
|
|
6
6
|
Project-URL: Source, https://github.com/zzctmac/inline-tdd
|
|
@@ -267,7 +267,7 @@ strip-itestdd path/to/file.py -o clean_file.py
|
|
|
267
267
|
You can also run it as a module:
|
|
268
268
|
|
|
269
269
|
```bash
|
|
270
|
-
python -m inline_tdd.strip path/to/file.py
|
|
270
|
+
python -m inline_tdd.strip path/to/file.py -i
|
|
271
271
|
```
|
|
272
272
|
|
|
273
273
|
**Before:**
|
|
@@ -184,3 +184,10 @@ def name_and_tag(a):
|
|
|
184
184
|
def name_tag_repeated(a):
|
|
185
185
|
itestdd(test_name="triple-check", repeated=3, tag=["core"]).given(a, 4).check_eq(b, 16)
|
|
186
186
|
b = a * 4
|
|
187
|
+
|
|
188
|
+
T = 12 * 4
|
|
189
|
+
def calculate_with_T(a):
|
|
190
|
+
itestdd().given(a, 3).check_eq(b, 51)
|
|
191
|
+
b = T + a
|
|
192
|
+
|
|
193
|
+
C = calculate_with_T(1)
|
|
@@ -28,6 +28,6 @@ def quicksort(arr, low=None, high=None):
|
|
|
28
28
|
quicksort(arr, pi + 1, high)
|
|
29
29
|
return arr
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
|
|
32
|
+
print(_partition([3, 6, 1, 8, 2], 0, 4))
|
|
33
|
+
print(quicksort([3, 6, 1, 8, 2]))
|
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.2.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 2,
|
|
31
|
+
__version__ = version = '1.2.7'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 2, 7)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -100,6 +100,13 @@ def pytest_addoption(parser: Parser) -> None:
|
|
|
100
100
|
help="order inlinetests",
|
|
101
101
|
dest="inlinetest_order",
|
|
102
102
|
)
|
|
103
|
+
parser.addoption(
|
|
104
|
+
"--inline-show-tests",
|
|
105
|
+
action="store_true",
|
|
106
|
+
default=False,
|
|
107
|
+
help="print the generated test code for each inline test",
|
|
108
|
+
dest="inline_show_tests",
|
|
109
|
+
)
|
|
103
110
|
|
|
104
111
|
|
|
105
112
|
@pytest.hookimpl()
|
|
@@ -1512,9 +1519,15 @@ class InlineTestRunner:
|
|
|
1512
1519
|
self._cleaned_funcs_cache[func_id] = cleaned
|
|
1513
1520
|
globs[name] = cleaned
|
|
1514
1521
|
|
|
1515
|
-
def run(self, test: InlineTest, out: List) -> None:
|
|
1522
|
+
def run(self, test: InlineTest, out: List, show: bool = False) -> None:
|
|
1516
1523
|
test_str = test.write_imports()
|
|
1517
1524
|
test_str += test.to_test()
|
|
1525
|
+
if show:
|
|
1526
|
+
print(f"\n{'='*60}")
|
|
1527
|
+
print(f"Generated test: {test.test_name} (line {test.lineno})")
|
|
1528
|
+
print(f"{'='*60}")
|
|
1529
|
+
print(test_str)
|
|
1530
|
+
print(f"{'='*60}")
|
|
1518
1531
|
tree = ast.parse(test_str)
|
|
1519
1532
|
codeobj = compile(tree, filename="<ast>", mode="exec")
|
|
1520
1533
|
self._prepare_globs(test.globs)
|
|
@@ -1590,9 +1603,10 @@ class InlinetestItem(pytest.Item):
|
|
|
1590
1603
|
def runtest(self) -> None:
|
|
1591
1604
|
assert self.dtest is not None
|
|
1592
1605
|
assert self.runner is not None
|
|
1606
|
+
show = self.config.getoption("inline_show_tests", False)
|
|
1593
1607
|
for round_index in range(1, self.dtest.repeated + 1):
|
|
1594
1608
|
failures: List[str] = []
|
|
1595
|
-
self.runner.run(copy.copy(self.dtest), failures)
|
|
1609
|
+
self.runner.run(copy.copy(self.dtest), failures, show=show)
|
|
1596
1610
|
if failures:
|
|
1597
1611
|
print(failures)
|
|
1598
1612
|
|
|
@@ -1626,6 +1640,67 @@ class InlinetestModule(pytest.Module):
|
|
|
1626
1640
|
|
|
1627
1641
|
return prio_sorted
|
|
1628
1642
|
|
|
1643
|
+
@staticmethod
|
|
1644
|
+
def _body_contains_itestdd(node):
|
|
1645
|
+
"""Return True if *node* (a FunctionDef) contains an itestdd() call."""
|
|
1646
|
+
for child in ast.walk(node):
|
|
1647
|
+
if not isinstance(child, ast.Call):
|
|
1648
|
+
continue
|
|
1649
|
+
inner = child
|
|
1650
|
+
while isinstance(inner, ast.Call):
|
|
1651
|
+
if isinstance(inner.func, ast.Name) and inner.func.id == "itestdd":
|
|
1652
|
+
return True
|
|
1653
|
+
if isinstance(inner.func, ast.Attribute) and isinstance(inner.func.value, ast.Call):
|
|
1654
|
+
inner = inner.func.value
|
|
1655
|
+
else:
|
|
1656
|
+
break
|
|
1657
|
+
return False
|
|
1658
|
+
|
|
1659
|
+
@staticmethod
|
|
1660
|
+
def _stmt_calls_any(stmt, func_names):
|
|
1661
|
+
"""Return True if *stmt* contains a direct call to any name in *func_names*."""
|
|
1662
|
+
for child in ast.walk(stmt):
|
|
1663
|
+
if isinstance(child, ast.Call) and isinstance(child.func, ast.Name):
|
|
1664
|
+
if child.func.id in func_names:
|
|
1665
|
+
return True
|
|
1666
|
+
return False
|
|
1667
|
+
|
|
1668
|
+
@staticmethod
|
|
1669
|
+
def _safe_import(file_path):
|
|
1670
|
+
"""Import *file_path* after stripping module-level statements that
|
|
1671
|
+
call functions containing itestdd() chains. Those statements would
|
|
1672
|
+
otherwise raise ``UnboundLocalError`` because TDD-mode itestdd()
|
|
1673
|
+
references variables before their assignment."""
|
|
1674
|
+
source = file_path.read_text(encoding="utf-8")
|
|
1675
|
+
tree = ast.parse(source, filename=str(file_path))
|
|
1676
|
+
|
|
1677
|
+
# 1. Identify top-level functions whose bodies contain itestdd().
|
|
1678
|
+
itestdd_func_names = set()
|
|
1679
|
+
for node in ast.iter_child_nodes(tree):
|
|
1680
|
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef)):
|
|
1681
|
+
if InlinetestModule._body_contains_itestdd(node):
|
|
1682
|
+
itestdd_func_names.add(node.name)
|
|
1683
|
+
|
|
1684
|
+
if not itestdd_func_names:
|
|
1685
|
+
# No itestdd-containing functions; nothing to strip.
|
|
1686
|
+
return None
|
|
1687
|
+
|
|
1688
|
+
# 2. Remove module-level statements that invoke those functions.
|
|
1689
|
+
new_body = [
|
|
1690
|
+
stmt for stmt in tree.body
|
|
1691
|
+
if not InlinetestModule._stmt_calls_any(stmt, itestdd_func_names)
|
|
1692
|
+
]
|
|
1693
|
+
tree.body = new_body
|
|
1694
|
+
ast.fix_missing_locations(tree)
|
|
1695
|
+
|
|
1696
|
+
# 3. Compile & exec into a fresh module object.
|
|
1697
|
+
mod = ModuleType(file_path.stem)
|
|
1698
|
+
mod.__file__ = str(file_path)
|
|
1699
|
+
code = compile(tree, str(file_path), "exec")
|
|
1700
|
+
exec(code, mod.__dict__)
|
|
1701
|
+
sys.modules[file_path.stem] = mod
|
|
1702
|
+
return mod
|
|
1703
|
+
|
|
1629
1704
|
def collect(self) -> Iterable[InlinetestItem]:
|
|
1630
1705
|
if self.path.name == "conftest.py":
|
|
1631
1706
|
module = self.config.pluginmanager._importconftest(
|
|
@@ -1637,6 +1712,13 @@ class InlinetestModule(pytest.Module):
|
|
|
1637
1712
|
try:
|
|
1638
1713
|
# TODO: still need to find the right way to import without errors. mode=ImportMode.importlib did not work
|
|
1639
1714
|
module = import_path(self.path, root=self.config.rootpath)
|
|
1715
|
+
except UnboundLocalError:
|
|
1716
|
+
# Module-level code calls a function containing itestdd()
|
|
1717
|
+
# which references TDD-mode variables before assignment.
|
|
1718
|
+
# Fall back to a safe import that strips those calls.
|
|
1719
|
+
module = self._safe_import(self.path)
|
|
1720
|
+
if module is None:
|
|
1721
|
+
raise
|
|
1640
1722
|
except Exception as e:
|
|
1641
1723
|
# (ImportError, ModuleNotFoundError, TypeError, NameError, FileNotFoundError)
|
|
1642
1724
|
if self.config.getvalue("inlinetest_ignore_import_errors"):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|