testsweet 0.2.1__tar.gz → 0.2.2__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 (112) hide show
  1. {testsweet-0.2.1 → testsweet-0.2.2}/CHANGELOG.md +13 -0
  2. {testsweet-0.2.1 → testsweet-0.2.2}/PKG-INFO +1 -1
  3. {testsweet-0.2.1 → testsweet-0.2.2}/pyproject.toml +1 -1
  4. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/__main__.py +7 -0
  5. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_loaders.py +0 -4
  6. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_targets.py +2 -2
  7. {testsweet-0.2.1 → testsweet-0.2.2}/tests/cli.py +13 -0
  8. testsweet-0.2.2/tests/fixtures/runner/uses_relative_import.py +8 -0
  9. {testsweet-0.2.1 → testsweet-0.2.2}/tests/targets.py +15 -0
  10. {testsweet-0.2.1 → testsweet-0.2.2}/uv.lock +1 -1
  11. {testsweet-0.2.1 → testsweet-0.2.2}/.github/workflows/lint.yml +0 -0
  12. {testsweet-0.2.1 → testsweet-0.2.2}/.github/workflows/publish.yml +0 -0
  13. {testsweet-0.2.1 → testsweet-0.2.2}/.github/workflows/tests.yml +0 -0
  14. {testsweet-0.2.1 → testsweet-0.2.2}/.github/workflows/types.yml +0 -0
  15. {testsweet-0.2.1 → testsweet-0.2.2}/.gitignore +0 -0
  16. {testsweet-0.2.1 → testsweet-0.2.2}/.pre-commit-config.yaml +0 -0
  17. {testsweet-0.2.1 → testsweet-0.2.2}/.python-version +0 -0
  18. {testsweet-0.2.1 → testsweet-0.2.2}/CLAUDE.md +0 -0
  19. {testsweet-0.2.1 → testsweet-0.2.2}/LICENSE +0 -0
  20. {testsweet-0.2.1 → testsweet-0.2.2}/README.md +0 -0
  21. {testsweet-0.2.1 → testsweet-0.2.2}/docs/contributing.md +0 -0
  22. {testsweet-0.2.1 → testsweet-0.2.2}/docs/examples/catches.py +0 -0
  23. {testsweet-0.2.1 → testsweet-0.2.2}/docs/examples/classes.py +0 -0
  24. {testsweet-0.2.1 → testsweet-0.2.2}/docs/examples/functions.py +0 -0
  25. {testsweet-0.2.1 → testsweet-0.2.2}/docs/getting-started.md +0 -0
  26. {testsweet-0.2.1 → testsweet-0.2.2}/docs/img/testsweet_200x200.png +0 -0
  27. {testsweet-0.2.1 → testsweet-0.2.2}/docs/reference.md +0 -0
  28. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/__init__.py +0 -0
  29. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_assertion.py +0 -0
  30. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_catches.py +0 -0
  31. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_class_helpers.py +0 -0
  32. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_classify.py +0 -0
  33. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_condition_decorator.py +0 -0
  34. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_config.py +0 -0
  35. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_discover.py +0 -0
  36. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_markers.py +0 -0
  37. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_outcomes.py +0 -0
  38. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_params.py +0 -0
  39. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_plugins.py +0 -0
  40. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_report.py +0 -0
  41. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_resolve.py +0 -0
  42. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_runner.py +0 -0
  43. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_skip.py +0 -0
  44. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_tag.py +0 -0
  45. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_tag_filter.py +0 -0
  46. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_walk.py +0 -0
  47. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/_xfail.py +0 -0
  48. {testsweet-0.2.1 → testsweet-0.2.2}/src/testsweet/py.typed +0 -0
  49. {testsweet-0.2.1 → testsweet-0.2.2}/tests/__init__.py +0 -0
  50. {testsweet-0.2.1 → testsweet-0.2.2}/tests/catches.py +0 -0
  51. {testsweet-0.2.1 → testsweet-0.2.2}/tests/config.py +0 -0
  52. {testsweet-0.2.1 → testsweet-0.2.2}/tests/discover.py +0 -0
  53. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/__init__.py +0 -0
  54. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/empty.py +0 -0
  55. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/imported_only.py +0 -0
  56. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/mixed.py +0 -0
  57. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/mixed_local_imported.py +0 -0
  58. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/multiple.py +0 -0
  59. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/non_callable_marker.py +0 -0
  60. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/__init__.py +0 -0
  61. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/all_pass.py +0 -0
  62. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/assertion_diagnostics.py +0 -0
  63. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_calls_recorded.py +0 -0
  64. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_decorated_simple.py +0 -0
  65. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_decorated_with_cm.py +0 -0
  66. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_enter_only.py +0 -0
  67. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_enter_raises.py +0 -0
  68. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_exit_raises.py +0 -0
  69. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_method_fails.py +0 -0
  70. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_mixed_with_function.py +0 -0
  71. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_simple.py +0 -0
  72. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_test_context_raises.py +0 -0
  73. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_test_context_with_params.py +0 -0
  74. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_with_inheritance.py +0 -0
  75. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_with_test_context.py +0 -0
  76. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/class_with_underscore_methods.py +0 -0
  77. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/empty.py +0 -0
  78. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/has_broken_import.py +0 -0
  79. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/has_failure.py +0 -0
  80. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/keyboard_interrupt.py +0 -0
  81. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/non_assertion_error.py +0 -0
  82. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/orphan_params.py +0 -0
  83. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/orphan_skip.py +0 -0
  84. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/orphan_tag.py +0 -0
  85. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/orphan_xfail.py +0 -0
  86. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_empty.py +0 -0
  87. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_generator.py +0 -0
  88. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_lazy_generator.py +0 -0
  89. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_lazy_list.py +0 -0
  90. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_lazy_on_class_method.py +0 -0
  91. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_no_decoration.py +0 -0
  92. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_on_class_method.py +0 -0
  93. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_simple.py +0 -0
  94. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/params_with_failure.py +0 -0
  95. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/skip_on_class_method.py +0 -0
  96. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/skip_on_params.py +0 -0
  97. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/tagged_class.py +0 -0
  98. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/runner/xfail_on_params.py +0 -0
  99. {testsweet-0.2.1 → testsweet-0.2.2}/tests/fixtures/single.py +0 -0
  100. {testsweet-0.2.1 → testsweet-0.2.2}/tests/markers.py +0 -0
  101. {testsweet-0.2.1 → testsweet-0.2.2}/tests/outcomes.py +0 -0
  102. {testsweet-0.2.1 → testsweet-0.2.2}/tests/params.py +0 -0
  103. {testsweet-0.2.1 → testsweet-0.2.2}/tests/plugins.py +0 -0
  104. {testsweet-0.2.1 → testsweet-0.2.2}/tests/report.py +0 -0
  105. {testsweet-0.2.1 → testsweet-0.2.2}/tests/resolve.py +0 -0
  106. {testsweet-0.2.1 → testsweet-0.2.2}/tests/runner.py +0 -0
  107. {testsweet-0.2.1 → testsweet-0.2.2}/tests/skip.py +0 -0
  108. {testsweet-0.2.1 → testsweet-0.2.2}/tests/tag.py +0 -0
  109. {testsweet-0.2.1 → testsweet-0.2.2}/tests/tag_filter.py +0 -0
  110. {testsweet-0.2.1 → testsweet-0.2.2}/tests/test_unittest_shim.py +0 -0
  111. {testsweet-0.2.1 → testsweet-0.2.2}/tests/walk.py +0 -0
  112. {testsweet-0.2.1 → testsweet-0.2.2}/tests/xfail.py +0 -0
@@ -1,6 +1,19 @@
1
1
  Changelog
2
2
  =========
3
3
 
4
+ [0.2.2] (2026-06-27)
5
+ --------------------
6
+
7
+ ### Bug Fixes
8
+
9
+ - Fixed loading a test file by path (e.g. `testsweet path/to/tests.py`)
10
+ when the module uses relative imports.
11
+ - Fixed resolving dotted targets (e.g. `testsweet tests.foo`) when run
12
+ via the installed `testsweet` console script.
13
+
14
+ [0.2.2]: https://github.com/kaapstorm/testsweet/releases/tag/v0.2.2
15
+
16
+
4
17
  [0.2.1] (2026-06-27)
5
18
  --------------------
6
19
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: testsweet
3
- Version: 0.2.1
3
+ Version: 0.2.2
4
4
  Summary: Python testing for humans
5
5
  Project-URL: Homepage, https://github.com/kaapstorm/testsweet
6
6
  Project-URL: Source, https://github.com/kaapstorm/testsweet
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "testsweet"
3
- version = "0.2.1"
3
+ version = "0.2.2"
4
4
  description = "Python testing for humans"
5
5
  license = "Apache-2.0"
6
6
  license-files = ["LICENSE"]
@@ -84,6 +84,13 @@ def main(argv: list[str]) -> int:
84
84
  if (include or exclude) else None
85
85
  )
86
86
  with scoped_sys_path():
87
+ # `python -m testsweet` prepends the cwd to sys.path, but the
88
+ # installed console script does not (sys.path[0] is its own bin
89
+ # directory). Put the cwd on the path so dotted targets resolve
90
+ # against the project the same way under both invocations.
91
+ cwd = str(pathlib.Path.cwd())
92
+ if cwd not in sys.path:
93
+ sys.path.insert(0, cwd)
87
94
  config = load_config(pathlib.Path.cwd())
88
95
  plugins = load_plugins()
89
96
  wrap_unit = unit_wrapper(plugins)
@@ -39,10 +39,6 @@ def _exec_module_from_path(path: pathlib.Path) -> ModuleType:
39
39
  return module
40
40
 
41
41
 
42
- def _load_path(target: str) -> ModuleType:
43
- return _exec_module_from_path(pathlib.Path(target).resolve())
44
-
45
-
46
42
  def _load_path_for_walk(path: pathlib.Path) -> ModuleType:
47
43
  info = _dotted_name_for_path(path)
48
44
  if info is None:
@@ -9,7 +9,7 @@ from types import ModuleType
9
9
 
10
10
  from testsweet._classify import _resolve_dotted
11
11
  from testsweet._config import DiscoveryConfig
12
- from testsweet._loaders import _load_path, _load_path_for_walk
12
+ from testsweet._loaders import _load_path_for_walk
13
13
  from testsweet._walk import (
14
14
  _build_exclude_set,
15
15
  _resolve_include_paths,
@@ -73,7 +73,7 @@ def parse_target(
73
73
  excluded=excluded,
74
74
  )
75
75
  ]
76
- return [(_load_path(target), None)]
76
+ return [(_load_path_for_walk(path), None)]
77
77
  return [_resolve_dotted(target)]
78
78
 
79
79
 
@@ -394,6 +394,19 @@ class Cli:
394
394
  assert result.returncode == 0
395
395
  assert result.stdout.startswith('Usage: testsweet')
396
396
 
397
+ def installed_entry_point_resolves_dotted_target(self):
398
+ script = pathlib.Path(sys.executable).with_name('testsweet')
399
+ if not script.exists():
400
+ return # not an installed environment; skip silently
401
+ result = subprocess.run(
402
+ [str(script), 'tests.fixtures.runner.all_pass'],
403
+ capture_output=True,
404
+ text=True,
405
+ cwd=_REPO_ROOT,
406
+ )
407
+ assert result.returncode == 0, result.stderr
408
+ assert 'passes_one ... ok' in result.stdout
409
+
397
410
  @params([(('-h',),), (('--help',),)])
398
411
  def help_flag_prints_usage_and_exits_zero(self, args):
399
412
  result = _run_cli(*args)
@@ -0,0 +1,8 @@
1
+ from testsweet import test
2
+
3
+ from .all_pass import passes_one # noqa: F401
4
+
5
+
6
+ @test
7
+ def uses_rel():
8
+ pass
@@ -65,6 +65,21 @@ class ParseTarget:
65
65
  assert module is expected
66
66
  assert names == expected_names
67
67
 
68
+ @params([
69
+ ('tests/fixtures/runner/uses_relative_import.py',),
70
+ ('./tests/fixtures/runner/uses_relative_import.py',),
71
+ (str((_FIXTURES / 'uses_relative_import.py').resolve()),),
72
+ ])
73
+ def file_path_with_relative_import(self, target):
74
+ # A file path to a module inside a package must be loaded with
75
+ # package context so its relative imports resolve, the same way
76
+ # the equivalent dotted name does.
77
+ result = parse_target(target)
78
+ assert len(result) == 1
79
+ module, names = result[0]
80
+ assert names is None
81
+ assert hasattr(module, 'uses_rel')
82
+
68
83
  def dotted_too_many_segments(self):
69
84
  with catch_exceptions() as excs:
70
85
  parse_target(
@@ -171,7 +171,7 @@ wheels = [
171
171
 
172
172
  [[package]]
173
173
  name = "testsweet"
174
- version = "0.2.0"
174
+ version = "0.2.2"
175
175
  source = { editable = "." }
176
176
 
177
177
  [package.dev-dependencies]
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