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.
Files changed (53) hide show
  1. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/.github/workflows/python-publish.yml +5 -1
  2. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/PKG-INFO +2 -2
  3. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/README.md +1 -1
  4. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/c.py +7 -0
  5. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/d.py +3 -3
  6. pytest_inline_tdd-1.2.7/integration-tests/tdd/e.py +6 -0
  7. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/__about__.py +2 -2
  8. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/plugin.py +84 -2
  9. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/.github/workflows/python-test.yml +0 -0
  10. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/.gitignore +0 -0
  11. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/LICENSE +0 -0
  12. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/changelog +0 -0
  13. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/convert_tests.py +0 -0
  14. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/convert_to_tdd.py +0 -0
  15. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/README.md +0 -0
  16. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/example.py +0 -0
  17. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/features.py +0 -0
  18. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/a.py +0 -0
  19. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/b.py +0 -0
  20. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/c.py +0 -0
  21. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo/parallel/d.py +0 -0
  22. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/demo_tdd.py +0 -0
  23. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/a.py +0 -0
  24. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/a.py.backup +0 -0
  25. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/b.py +0 -0
  26. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/c.py +0 -0
  27. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/d.py +0 -0
  28. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/e.py +0 -0
  29. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/f.py +0 -0
  30. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/g.py +0 -0
  31. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/h.py +0 -0
  32. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/i.py +0 -0
  33. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/test_files/j.py +0 -0
  34. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/parallelization/time-parallel-tests.sh +0 -0
  35. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/a.py +0 -0
  36. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/a1.py +0 -0
  37. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/b.py +0 -0
  38. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/d.bak +0 -0
  39. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/db.py +0 -0
  40. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/integration-tests/tdd/np_ops.py +0 -0
  41. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/prepare-conda-env.sh +0 -0
  42. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/pyproject.toml +0 -0
  43. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/__init__.py +0 -0
  44. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/ast_future.py +0 -0
  45. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/inline.py +0 -0
  46. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/src/inline_tdd/strip.py +0 -0
  47. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tdd_summary.py +0 -0
  48. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/test_tdd.py +0 -0
  49. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/test_tdd_verification.py +0 -0
  50. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tests/__init__.py +0 -0
  51. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tests/test_plugin.py +0 -0
  52. {pytest_inline_tdd-1.2.4 → pytest_inline_tdd-1.2.7}/tests/test_plugin.py.bak +0 -0
  53. {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
- run: python -m build
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.4
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 --i
270
+ python -m inline_tdd.strip path/to/file.py -i
271
271
  ```
272
272
 
273
273
  **Before:**
@@ -216,7 +216,7 @@ strip-itestdd path/to/file.py -o clean_file.py
216
216
  You can also run it as a module:
217
217
 
218
218
  ```bash
219
- python -m inline_tdd.strip path/to/file.py --i
219
+ python -m inline_tdd.strip path/to/file.py -i
220
220
  ```
221
221
 
222
222
  **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
- if __name__ == "__main__":
32
- print(_partition([3, 6, 1, 8, 2], 0, 4))
33
- print(quicksort([3, 6, 1, 8, 2]))
31
+
32
+ print(_partition([3, 6, 1, 8, 2], 0, 4))
33
+ print(quicksort([3, 6, 1, 8, 2]))
@@ -0,0 +1,6 @@
1
+ from inline_tdd import itestdd
2
+ class Calculator:
3
+ def add(self, a, b):
4
+ itestdd().given(a, 2).given(b, 3).check_eq(result, 5)
5
+ result = a + b
6
+ return result
@@ -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.4'
32
- __version_tuple__ = version_tuple = (1, 2, 4)
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"):