assertpy2 2.3.8__tar.gz → 2.4.0__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.
- {assertpy2-2.3.8 → assertpy2-2.4.0}/PKG-INFO +16 -3
- {assertpy2-2.3.8 → assertpy2-2.4.0}/README.md +15 -2
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/assertpy.py +1 -1
- {assertpy2-2.3.8 → assertpy2-2.4.0}/pyproject.toml +1 -1
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.codecov.yml +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.github/dependabot.yml +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.github/workflows/ci.yml +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.github/workflows/codeql.yml +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.github/workflows/publish.yml +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.github/workflows/scorecard.yml +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.github/workflows/zizmor.yml +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/.gitignore +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/CONTRIBUTING.md +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/LICENSE +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/SECURITY.md +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/__init__.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/_mixin_base.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/_typing.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/async_assertions.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/base.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/behave_matchers.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/bytes_mixin.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/collection.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/contains.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/date.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/dict.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/dynamic.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/errors.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/exception.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/extracting.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/file.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/helpers.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/json_mixin.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/matchers.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/numeric.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/py.typed +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/pytest_plugin.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/snapshot.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/assertpy2/string.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/docs/api.md +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/docs/logo-dark.svg +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/docs/logo.svg +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_async.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_behave_matchers.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_bool.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_bytes.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_class.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_collection.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_core.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_custom_dict.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_custom_list.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_datetime.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_description.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_dict.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_dict_compare.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_dyn.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_equals.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_errors.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_expected_exception.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_extensions.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_extracting.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_fail.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_file.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_grouped_soft.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_in.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_json.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_list.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_matcher_registry.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_matchers.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_matchers_phase3.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_namedtuple.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_none.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_not.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_numbers.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_overloads.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_phase2.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_pipeline.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_pytest_plugin.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_readme.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_regex_groups.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_rich_diff.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_same_as.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_snapshots.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_soft.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_soft_fail.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_string.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_structural.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_traceback.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_type.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/tests/test_warn.py +0 -0
- {assertpy2-2.3.8 → assertpy2-2.4.0}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: assertpy2
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.4.0
|
|
4
4
|
Summary: Fluent assertion library for Python with composable matchers, structural matching, and full type safety
|
|
5
5
|
Project-URL: Homepage, https://github.com/Solganis/assertpy2
|
|
6
6
|
Project-URL: Repository, https://github.com/Solganis/assertpy2
|
|
@@ -126,6 +126,19 @@ diff (dict):
|
|
|
126
126
|
+ 99
|
|
127
127
|
```
|
|
128
128
|
|
|
129
|
+
## Type-aware autocomplete
|
|
130
|
+
|
|
131
|
+
`assert_that()` uses `@overload` to return type-specific Protocols.
|
|
132
|
+
Your IDE shows only methods relevant to the value you're testing, not all 100+:
|
|
133
|
+
|
|
134
|
+
- `assert_that("hello").` → string methods: `starts_with`, `matches`, `is_alpha`, ...
|
|
135
|
+
- `assert_that(42).` → numeric methods: `is_positive`, `is_between`, `is_close_to`, ...
|
|
136
|
+
- `assert_that(Path("/tmp")).` → path methods: `exists`, `is_file`, `is_readable`, ...
|
|
137
|
+
- `assert_that(my_dict).` → dict methods: `contains_key`, `contains_entry`, `has_json_path`, ...
|
|
138
|
+
- `assert_that(b"\x89PNG").` → bytes methods: `starts_with_bytes`, `is_valid_utf8`, `decoded_as`, ...
|
|
139
|
+
|
|
140
|
+
9 type-specific Protocols instead of one `Any`. Works in PyCharm, VS Code, and any LSP-compatible editor.
|
|
141
|
+
|
|
129
142
|
---
|
|
130
143
|
|
|
131
144
|
## Comparison
|
|
@@ -135,7 +148,7 @@ diff (dict):
|
|
|
135
148
|
| | pytest assert | PyHamcrest | assertpy | **assertpy2** |
|
|
136
149
|
|---|:---:|:---:|:---:|:---:|
|
|
137
150
|
| **Type safety** | Partial (mypy plugin) | No | No | **py.typed, @overload, Self** |
|
|
138
|
-
| **IDE autocomplete** | Generic | Generic | Generic | **
|
|
151
|
+
| **IDE autocomplete** | Generic | Generic | Generic | **[Filtered by type](#type-aware-autocomplete)** |
|
|
139
152
|
| **Fluent chaining** | No | No | Yes | **Yes** |
|
|
140
153
|
| **Composable matchers** | No | Yes (functions) | No | **Yes (`&` `\|` `~` operators)** |
|
|
141
154
|
| **Structural matching** | No | Flat (has_entries) | No | **Recursive with matchers** |
|
|
@@ -198,7 +211,7 @@ assert_that(items).is_type_of(list).is_length(3).contains("admin")
|
|
|
198
211
|
|
|
199
212
|
**Type safety**
|
|
200
213
|
|
|
201
|
-
- **
|
|
214
|
+
- [**Type-aware autocomplete**](#type-aware-autocomplete): 9 Protocols, IDE shows only relevant methods per type.
|
|
202
215
|
- **py.typed**: `Self` return types, PEP 561 compliant ([PEP 561](https://peps.python.org/pep-0561/)).
|
|
203
216
|
|
|
204
217
|
**Extensibility**
|
|
@@ -88,6 +88,19 @@ diff (dict):
|
|
|
88
88
|
+ 99
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
## Type-aware autocomplete
|
|
92
|
+
|
|
93
|
+
`assert_that()` uses `@overload` to return type-specific Protocols.
|
|
94
|
+
Your IDE shows only methods relevant to the value you're testing, not all 100+:
|
|
95
|
+
|
|
96
|
+
- `assert_that("hello").` → string methods: `starts_with`, `matches`, `is_alpha`, ...
|
|
97
|
+
- `assert_that(42).` → numeric methods: `is_positive`, `is_between`, `is_close_to`, ...
|
|
98
|
+
- `assert_that(Path("/tmp")).` → path methods: `exists`, `is_file`, `is_readable`, ...
|
|
99
|
+
- `assert_that(my_dict).` → dict methods: `contains_key`, `contains_entry`, `has_json_path`, ...
|
|
100
|
+
- `assert_that(b"\x89PNG").` → bytes methods: `starts_with_bytes`, `is_valid_utf8`, `decoded_as`, ...
|
|
101
|
+
|
|
102
|
+
9 type-specific Protocols instead of one `Any`. Works in PyCharm, VS Code, and any LSP-compatible editor.
|
|
103
|
+
|
|
91
104
|
---
|
|
92
105
|
|
|
93
106
|
## Comparison
|
|
@@ -97,7 +110,7 @@ diff (dict):
|
|
|
97
110
|
| | pytest assert | PyHamcrest | assertpy | **assertpy2** |
|
|
98
111
|
|---|:---:|:---:|:---:|:---:|
|
|
99
112
|
| **Type safety** | Partial (mypy plugin) | No | No | **py.typed, @overload, Self** |
|
|
100
|
-
| **IDE autocomplete** | Generic | Generic | Generic | **
|
|
113
|
+
| **IDE autocomplete** | Generic | Generic | Generic | **[Filtered by type](#type-aware-autocomplete)** |
|
|
101
114
|
| **Fluent chaining** | No | No | Yes | **Yes** |
|
|
102
115
|
| **Composable matchers** | No | Yes (functions) | No | **Yes (`&` `\|` `~` operators)** |
|
|
103
116
|
| **Structural matching** | No | Flat (has_entries) | No | **Recursive with matchers** |
|
|
@@ -160,7 +173,7 @@ assert_that(items).is_type_of(list).is_length(3).contains("admin")
|
|
|
160
173
|
|
|
161
174
|
**Type safety**
|
|
162
175
|
|
|
163
|
-
- **
|
|
176
|
+
- [**Type-aware autocomplete**](#type-aware-autocomplete): 9 Protocols, IDE shows only relevant methods per type.
|
|
164
177
|
- **py.typed**: `Self` return types, PEP 561 compliant ([PEP 561](https://peps.python.org/pep-0561/)).
|
|
165
178
|
|
|
166
179
|
**Extensibility**
|
|
@@ -47,7 +47,7 @@ from .numeric import NumericMixin
|
|
|
47
47
|
from .snapshot import SnapshotMixin
|
|
48
48
|
from .string import StringMixin
|
|
49
49
|
|
|
50
|
-
__version__ = "2.
|
|
50
|
+
__version__ = "2.4.0"
|
|
51
51
|
|
|
52
52
|
__tracebackhide__ = True # clean tracebacks via py.test integration
|
|
53
53
|
contextlib.__tracebackhide__ = True # ty: ignore[unresolved-attribute] # pytest monkey-patch
|
|
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
|
|
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
|