New upstream version 2.0.3
Ileana Dumitrescu
1 year, 7 months ago
0 | --- | |
1 | name: CI | |
2 | ||
3 | on: | |
4 | push: | |
5 | branches: ["main", "master", "ci-testing-*"] | |
6 | ||
7 | pull_request: | |
8 | branches: ["main", "master"] | |
9 | ||
10 | workflow_dispatch: | |
11 | ||
12 | jobs: | |
13 | tests: | |
14 | name: "Python ${{ matrix.python-version }} / ${{ matrix.os }}" | |
15 | runs-on: "${{ matrix.os }}" | |
16 | env: | |
17 | USING_COVERAGE: "3.7,3.8,3.9,3.10" | |
18 | ||
19 | strategy: | |
20 | matrix: | |
21 | os: [ubuntu-latest, macos-latest, windows-latest] | |
22 | python-version: | |
23 | - "3.6" | |
24 | - "3.7" | |
25 | - "3.8" | |
26 | - "3.9" | |
27 | - "3.10.0" | |
28 | - "pypy2" | |
29 | - "pypy3" | |
30 | exclude: | |
31 | - os: macos-latest | |
32 | python-version: pypy3 | |
33 | ||
34 | steps: | |
35 | - uses: "actions/checkout@v2" | |
36 | - uses: "actions/setup-python@v2" | |
37 | with: | |
38 | python-version: "${{ matrix.python-version }}" | |
39 | - name: "Install dependencies" | |
40 | run: | | |
41 | python -VV | |
42 | python -msite | |
43 | python -m pip install --upgrade pip setuptools wheel | |
44 | python -m pip install --upgrade coverage[toml] virtualenv tox tox-gh-actions | |
45 | ||
46 | - name: "Run tox targets for ${{ matrix.python-version }}" | |
47 | run: "python -m tox" | |
48 | ||
49 | - name: Upload coverage data | |
50 | uses: actions/upload-artifact@v2 | |
51 | with: | |
52 | name: coverage-data | |
53 | path: ".coverage.*" | |
54 | if-no-files-found: ignore | |
55 | ||
56 | coverage: | |
57 | needs: | |
58 | - tests | |
59 | runs-on: ubuntu-latest | |
60 | steps: | |
61 | - uses: actions/checkout@v2 | |
62 | - uses: actions/setup-python@v2 | |
63 | with: | |
64 | python-version: "3.10" | |
65 | ||
66 | - name: Install coverage | |
67 | run: python -m pip install --upgrade coverage[toml] | |
68 | ||
69 | - name: Download coverage data | |
70 | uses: actions/download-artifact@v2 | |
71 | with: | |
72 | name: coverage-data | |
73 | ||
74 | - name: Combine coverage | |
75 | run: python -m coverage combine | |
76 | ||
77 | # ignore-errors is so that we don't gag on missing code in .tox environments | |
78 | - name: Generate the HTML report | |
79 | run: python -m coverage html --skip-covered --skip-empty --ignore-errors | |
80 | ||
81 | - name: Upload the HTML report | |
82 | uses: actions/upload-artifact@v2 | |
83 | with: | |
84 | name: html-report | |
85 | path: htmlcov | |
86 | ||
87 | # ignore-errors is so that we don't gag on missing code in .tox environments | |
88 | - name: Enforce the coverage | |
89 | run: python -m coverage report --ignore-errors --fail-under 95 | |
90 | ||
91 | package: | |
92 | name: "Build & verify package" | |
93 | runs-on: "ubuntu-latest" | |
94 | ||
95 | steps: | |
96 | - uses: "actions/checkout@v2" | |
97 | - uses: "actions/setup-python@v1" | |
98 | with: | |
99 | python-version: "3.10" | |
100 | ||
101 | - name: Check if we have the publish key | |
102 | env: | |
103 | TEST_PYPI_API_TOKEN: ${{ secrets.TEST_PYPI_API_TOKEN }} | |
104 | if: "${{ env.TEST_PYPI_API_TOKEN != '' }}" | |
105 | run: | | |
106 | echo "DO_PUBLISH=yes" >> $GITHUB_ENV | |
107 | ||
108 | - name: "Install pep517 and twine" | |
109 | run: "python -m pip install pep517 twine" | |
110 | - name: "Build package" | |
111 | run: "python -m pep517.build --source --binary ." | |
112 | - name: "List result" | |
113 | run: "ls -l dist" | |
114 | - name: "Check long_description" | |
115 | run: "python -m twine check dist/*" | |
116 | - name: "Publish package to TestPyPI" | |
117 | uses: "pypa/gh-action-pypi-publish@release/v1" | |
118 | if: "${{ env.DO_PUBLISH == 'yes' }}" | |
119 | with: | |
120 | user: "__token__" | |
121 | password: "${{ secrets.TEST_PYPI_API_TOKEN }}" | |
122 | repository_url: "https://test.pypi.org/legacy/" | |
123 | skip_existing: true | |
124 | ||
125 | install-dev: | |
126 | strategy: | |
127 | matrix: | |
128 | os: ["ubuntu-latest", "windows-latest", "macos-latest"] | |
129 | ||
130 | name: "Verify dev env / ${{ matrix.os }}" | |
131 | runs-on: "${{ matrix.os }}" | |
132 | ||
133 | steps: | |
134 | - uses: "actions/checkout@v2" | |
135 | - uses: "actions/setup-python@v2" | |
136 | with: | |
137 | python-version: "3.9" | |
138 | - name: "Install in dev mode" | |
139 | run: "python -m pip install -e .[dev]" | |
140 | - name: "Import package" | |
141 | run: "python -c 'import hamcrest; print(hamcrest.__version__)'" |
3 | 3 | build/ |
4 | 4 | dist/ |
5 | 5 | .tox |
6 | .coverage | |
6 | .coverage* | |
7 | 7 | .idea/ |
8 | 8 | *~ |
9 | 9 | .python-version |
10 | 10 | .mypy_cache/ |
11 | requirements.txt | |
12 | requirements.in |
0 | repos: | |
1 | - repo: meta | |
2 | hooks: | |
3 | - id: check-hooks-apply | |
4 | - id: check-useless-excludes | |
5 | ||
6 | - repo: https://github.com/pre-commit/pre-commit-hooks | |
7 | rev: v4.0.1 | |
8 | hooks: | |
9 | - id: debug-statements | |
10 | ||
11 | - repo: https://github.com/asottile/blacken-docs | |
12 | rev: v1.12.0 | |
13 | hooks: | |
14 | - id: blacken-docs | |
15 | # args: ["-l100"] | |
16 | ||
17 | - repo: https://github.com/PyCQA/flake8 | |
18 | rev: 4.0.1 | |
19 | hooks: | |
20 | - id: flake8 | |
21 | exclude: >- | |
22 | (?x)^( | |
23 | examples/.*\.py$ | |
24 | | doc/.*\.py$ | |
25 | ) | |
26 | ||
27 | - repo: https://github.com/psf/black | |
28 | rev: 21.12b0 | |
29 | hooks: | |
30 | - id: black | |
31 | # args: ["-l100"] |
0 | --- | |
1 | version: 2 | |
2 | python: | |
3 | # Keep version in sync with tox.ini (docs and gh-actions). | |
4 | version: 3.7 | |
5 | ||
6 | install: | |
7 | - method: pip | |
8 | path: . | |
9 | extra_requirements: | |
10 | - docs |
0 | language: python | |
1 | dist: xenial | |
2 | ||
3 | matrix: | |
4 | include: | |
5 | - python: 3.5 | |
6 | env: | |
7 | - TOX_ENV=py35 | |
8 | - python: 3.6 | |
9 | env: | |
10 | - TOX_ENV=py36 | |
11 | - python: 3.6 | |
12 | env: | |
13 | - TOX_ENV=pypy3.6 | |
14 | - python: 3.6 | |
15 | env: | |
16 | - TOX_ENV=py36-numpy | |
17 | - python: 3.7 | |
18 | sudo: yes | |
19 | env: | |
20 | - TOX_ENV=py37 | |
21 | - python: 3.8 | |
22 | sudo: yes | |
23 | env: | |
24 | - TOX_ENV=py38 | |
25 | - os: osx | |
26 | language: generic | |
27 | python: 3.7 | |
28 | env: | |
29 | - TOX_ENV=py37 | |
30 | - os: windows | |
31 | language: sh | |
32 | python: 3.7 | |
33 | before_install: | |
34 | - choco install python --version=3.7.5 | |
35 | - export PATH="/c/Python37:/c/Python37/Scripts:$PATH" | |
36 | - python -m pip install --upgrade pip wheel | |
37 | env: | |
38 | - TOX_ENV=py37 | |
39 | - python: 3.6 | |
40 | env: | |
41 | - TOX_ENV=docs-py3 | |
42 | - python: 3.7 | |
43 | env: | |
44 | - TOX_ENV=check-format | |
45 | - python: 3.8 | |
46 | env: | |
47 | - TOX_ENV=mypy | |
48 | ||
49 | before_install: | |
50 | - export EASY_SETUP_URL='http://peak.telecommunity.com/dist/ez_setup.py' | |
51 | ||
52 | install: | |
53 | - pip install --upgrade pip tox coveralls | |
54 | - python --version | |
55 | - pip --version | |
56 | ||
57 | script: | |
58 | - tox -e $TOX_ENV | |
59 | ||
60 | after_success: | |
61 | - coveralls |
0 | 2.0.3 (2021-12-12) | |
1 | ------------------ | |
2 | ||
3 | Features ^^^^^^^^ | |
4 | ||
5 | - * Adds the tests to the sdist. Fixed by #150 | |
6 | ||
7 | `#141 <https://github.com/hamcrest/PyHamcrest/issues/141>`_ | |
8 | - * Update the CI to test Python 3.10 | |
9 | ||
10 | `#160 <https://github.com/hamcrest/PyHamcrest/issues/160>`_ | |
11 | - * Add pretty string representation for matchers objects | |
12 | ||
13 | `#170 <https://github.com/hamcrest/PyHamcrest/issues/170>`_ | |
14 | ||
15 | ||
16 | Bugfixes ^^^^^^^^ | |
17 | ||
18 | - * Test coverage is now submitted to codecov.io. | |
19 | ||
20 | Fixed by #150 | |
21 | ||
22 | `#135 <https://github.com/hamcrest/PyHamcrest/issues/135>`_ | |
23 | - Change to the ``has_entry()`` matcher - if exactly one key matches, but the value does not, report only the mismatching | |
24 | value. | |
25 | ||
26 | Fixed by #157 | |
27 | ||
28 | `#156 <https://github.com/hamcrest/PyHamcrest/issues/156>`_ | |
29 | - * Fix is_() type annotations | |
30 | ||
31 | `#180 <https://github.com/hamcrest/PyHamcrest/issues/180>`_ | |
32 | ||
33 | ||
34 | Misc ^^^^ | |
35 | ||
36 | - `#150 <https://github.com/hamcrest/PyHamcrest/issues/150>`_, `#159 <https://github.com/hamcrest/PyHamcrest/issues/159>`_, `#162 <https://github.com/hamcrest/PyHamcrest/issues/162>`_, `#163 <https://github.com/hamcrest/PyHamcrest/issues/163>`_, `#166 <https://github.com/hamcrest/PyHamcrest/issues/166>`_, `#175 <https://github.com/hamcrest/PyHamcrest/issues/175>`_ | |
37 | ||
38 | ||
39 | ---- | |
40 | ||
41 | ||
42 | Changelog | |
43 | ========= | |
44 | ||
45 | Version 2.0.2 | |
46 | ------------- | |
47 | ||
48 | Various type hint bug fixes. | |
49 | ||
50 | Version 2.0.1 | |
51 | ------------- | |
52 | ||
53 | * Make hamcrest package PEP 561 compatible, i.e. supply type hints for external use. | |
54 | ||
55 | Version 2.0.0 | |
56 | ------------- | |
57 | ||
58 | Drop formal support for 2.x | |
59 | Drop formal support for 3.x < 3.5 | |
60 | ||
61 | Fix #128 - raises() grows support for additional matchers on exception object. | |
62 | ||
63 | * Made has_properties() report all mismatches, not just the first. | |
64 | * Silence warnings. | |
65 | * Type fixes. | |
66 | * Remove obsolete dependencies. | |
67 | ||
68 | Version 1.10.1 | |
69 | -------------- | |
70 | ||
71 | Add support up to Python 3.8 | |
72 | ||
73 | Fix #66 - deprecate contains() in favour of contains_exactly(). | |
74 | Fix #72 - make has_properties mismatch description less verbose by adding option to AllOf not to include matcher description in its mismatch messages. | |
75 | Fix #82 - include exception details in mismatch description. | |
76 | ||
77 | Version 1.9.0 | |
78 | ------------- | |
79 | ||
80 | Drop formal support for 2.x < 2.7 | |
81 | Drop formal support for 3.x < 3.4 | |
82 | ||
83 | Fix #62 - Return result of a deferred call | |
84 | ||
85 | Version 1.8.5 | |
86 | ------------- | |
87 | ||
88 | Fix #56 - incorrect handling of () in is_ matcher | |
89 | Fix #60 - correct calling API call with args | |
90 | ||
91 | Version 1.8.4 | |
92 | ------------- | |
93 | ||
94 | * Fix #54 - Make instance_of work with tuple like isinstance and unittest's assertIsInstance | |
95 | ||
96 | Version 1.8.3 | |
97 | ------------- | |
98 | ||
99 | * Fix #52 - bad handling when reporting mismatches for byte arrays in Python 3 | |
100 | ||
101 | Version 1.8.2 | |
102 | ------------- | |
103 | ||
104 | * [Bug] Fix unicode syntax via u() introduction (puppsman) | |
105 | ||
106 | Version 1.8.1 | |
107 | ------------- | |
108 | ||
109 | * Added not_ alias for is_not [Matteo Bertini] | |
110 | * Added doc directory to the sdist [Alex Brandt] | |
111 | ||
112 | Version 1.8 | |
113 | ----------- | |
114 | ||
115 | * Supported versions | |
116 | - Support for Python 2.5 and Jython 2.5 has been dropped. They may still work, but no promises. | |
117 | ||
118 | * Bug Fixes | |
119 | - [#39] is_empty was missing from the global namespace | |
120 | ||
121 | * New Features | |
122 | - Support for numpy numeric values in iscloseto (Alexander Beedie) | |
123 | - A matcher targeting exceptions and call results (Per Fagrell) | |
124 | ||
125 | Version 1.7 | |
126 | ----------- | |
127 | ||
128 | 2 Sep 2013 (Version 1.7.2) | |
129 | * Supported versions | |
130 | - As of this version, support for Python 3.1 has been dropped due to no available CI platform. | |
131 | - Added support for Python 3.3 | |
132 | ||
133 | * Bug fixes: | |
134 | - string_contains_in_order is now used in the test as it would be in an application, and is properly exported. (Romilly Cocking) | |
135 | - Fix mismatch description of containing_inanyorder (David Keijser) | |
136 | - added import of stringmatches to text/__init__.py (Eric Scheidemantle) | |
137 | - added matches_regexp to __all__ list to library/__init__.py (Eric Scheidemantle) | |
138 | ||
139 | 5 Jan 2010 (Version 1.7.1) | |
140 | * Bug fixes: | |
141 | - included a fix by jaimegildesagredo for issue #28 (has_properties was not importable) | |
142 | - included a fix by keys for contains_inanyorder | |
143 | ||
144 | 29 Dec 2012 | |
145 | (All changes by Chris Rose unless otherwise noted.) | |
146 | ||
147 | * New matchers: | |
148 | - matches_regexp matches a regular expression in a string. | |
149 | - has_properties matches an object with more than one property. | |
150 | - is_empty matches any object with length 0. | |
151 | ||
152 | * Improvements: | |
153 | - Can now do matching against old-style classes. | |
154 | - Sequence matchers handle generators, as well as actual sequences and | |
155 | pseudo-sequences. | |
156 | - README enhancements by ming13 | |
157 | ||
158 | ||
159 | Version 1.6 | |
160 | ----------- | |
161 | ||
162 | 27 Sep 2011 | |
163 | (All changes by Chris Rose unless otherwise noted.) | |
164 | ||
165 | * Packaging: | |
166 | - Python 3.2 support. | |
167 | ||
168 | * New matchers: | |
169 | - has_property('property_name', value_matcher) matches if object has a property with a given name whose value satisfies a given matcher. | |
170 | ||
171 | * Improvements: | |
172 | - hasEntries supports two new calling conventions: | |
173 | has_entries({'key' : value_matcher, 'key_2' : other_value_matcher}) | |
174 | has_entries(key=value_matcher, key_2=other_value_matcher) | |
175 | - Describe Unicode strings by their __repr__. Thanks to: Sebastian Arming | |
176 | - Rewrote documentation. (Jon Reid) | |
177 | ||
178 | ||
179 | Version 1.5 | |
180 | ----------- | |
181 | ||
182 | 29 Apr 2011 | |
183 | * Packaging: | |
184 | - Python 3.1 support. Thanks to: Chris Rose | |
185 | - Easier installation with bootstrapping. Thanks to: Chris Rose | |
186 | ||
187 | * Mock integration: | |
188 | - "match_equality" wraps a matcher to define equality in terms of satisfying the matcher. This allows Hamcrest matchers to be used in libraries that are not Hamcrest-aware, such as Michael Foord's mock library. Thanks to: Chris Rose | |
189 | ||
190 | * New matcher: | |
191 | - "string_contains_in_order" matches string containing given list of substrings, in order. Thanks to: Romilly Cocking | |
192 | ||
193 | * Improved matchers: | |
194 | - For consistency, changed "any_of" and "all_of" to implicitly wrap non-matcher values in EqualTo. Thanks to: Chris Rose | |
195 | - Changed "sameInstance" mismatch description to omit address when describing | |
196 | None. | |
197 | ||
198 | ||
199 | Version 1.4 | |
200 | ----------- | |
201 | ||
202 | 13 Feb 2011 | |
203 | * New matchers: | |
204 | - "has_entries" matches dictionary containing key-value pairs satisfying a given list of alternating keys and value matchers. | |
205 | ||
206 | * "assert_that" can be invoked with a single boolean argument; the reason message is now optional. This is a convenience replacement for assertTrue. Thanks to: Jeong-Min Lee | |
207 | ||
208 | * Improved descriptions: | |
209 | - Reverted 1.3 change: Describe None as "<None>" after all, since it is an object. | |
210 | - "is_" no longer says "is ..." in its description, but just lets the inner description pass through. | |
211 | - Consistently use articles to begin descriptions, such as "a sequence containing" instead of "sequence containing". | |
212 | ||
213 | ||
214 | Version 1.3 | |
215 | ----------- | |
216 | ||
217 | 04 Feb 2011 | |
218 | * PyHamcrest is now compatible with Python 3! To install PyHamcrest on Python 3: | |
219 | - Install the "distribute" package, http://pypi.python.org/pypi/distribute | |
220 | - Run "python3 setup.py install" | |
221 | Unit tests are not converted by the install procedure. Run "2to3 -nw ." separately to convert them. You may discover import statements in the __init__.py files (and one in core/base_description.py) that need dot prefixes. | |
222 | Thanks to: Jeong-Min Lee | |
223 | ||
224 | * Improved descriptions and mismatch descriptions of several matchers, including: | |
225 | - Fixed "contains" and "contains_inanyorder" to describe mismatch if item is not a sequence. | |
226 | - Fixed "described_as" to use nested matcher to generate mismatch description. | |
227 | - "same_instance" is more readable, and includes object memory addresses. | |
228 | - If object has a length, "has_length" mismatch describes actual length. | |
229 | - Describe None as "None" instead of "<None>". | |
230 | - Don't wrap angle brackets around a description that already has them. | |
231 | - Improved readability of several matchers. | |
232 | ||
233 | ||
234 | Version 1.2.1 | |
235 | ------------- | |
236 | ||
237 | 04 Jan 2011 | |
238 | * Fixed "assert_that" to describe the diagnosis of the mismatch, not just the | |
239 | mismatched value. PyHamcrest will now give even more useful information. | |
240 | ||
241 | * Expanded BaseDescription.append_description_of to handle all types of values, not just self-describing values. | |
242 | ||
243 | * Deprecated: | |
244 | - Description.append_value no longer needed; call append_description_of instead. | |
245 | - BaseDescription.append_value_list no longer needed; call append_list instead. | |
246 | - SelfDescribingValue no longer needed. | |
247 | ||
248 | 1.2.1 fixes to 1.2: | |
249 | - Corrected manifest so install works. Thanks to: Jeong-Min Lee | |
250 | ||
251 | ||
252 | Version 1.1 | |
253 | ----------- | |
254 | ||
255 | 28 Dec 2010 | |
256 | * New matchers: | |
257 | - "contains" matches sequence containing matching items in order. | |
258 | - "contains_inanyorder" matches sequence containing matching items in any order. | |
259 | ||
260 | * Added Sphinx documentation support. | |
261 | ||
262 | ||
263 | Version 1.0 | |
264 | ----------- | |
265 | ||
266 | 04 Dec 2010 | |
267 | * First official release | |
268 | * Text matchers now support Unicode strings | |
269 | ||
270 | 15 Jan 2008 | |
271 | * Initial submission |
0 | === Version 2.0.2 === | |
1 | ||
2 | Various type hint bug fixes. | |
3 | ||
4 | === Version 2.0.1 === | |
5 | ||
6 | * Make hamcrest package PEP 561 compatible, i.e. supply type hints for external use. | |
7 | ||
8 | === Version 2.0.0 == | |
9 | ||
10 | Drop formal support for 2.x | |
11 | Drop formal support for 3.x < 3.5 | |
12 | ||
13 | Fix #128 - raises() grows support for additional matchers on exception object. | |
14 | ||
15 | * Made has_properties() report all mismatches, not just the first. | |
16 | * Silence warnings. | |
17 | * Type fixes. | |
18 | * Remove obsolete dependencies. | |
19 | ||
20 | === Version 1.10.1 == | |
21 | ||
22 | Add support up to Python 3.8 | |
23 | ||
24 | Fix #66 - deprecate contains() in favour of contains_exactly(). | |
25 | Fix #72 - make has_properties mismatch description less verbose by adding option to AllOf not to include matcher description in its mismatch messages. | |
26 | Fix #82 - include exception details in mismatch description. | |
27 | ||
28 | === Version 1.9.0 == | |
29 | ||
30 | Drop formal support for 2.x < 2.7 | |
31 | Drop formal support for 3.x < 3.4 | |
32 | ||
33 | Fix #62 - Return result of a deferred call | |
34 | ||
35 | === Version 1.8.5 === | |
36 | ||
37 | Fix #56 - incorrect handling of () in is_ matcher | |
38 | Fix #60 - correct calling API call with args | |
39 | ||
40 | === Version 1.8.4 == | |
41 | ||
42 | * Fix #54 - Make instance_of work with tuple like isinstance and unittest's assertIsInstance | |
43 | ||
44 | === Version 1.8.3 === | |
45 | ||
46 | * Fix #52 - bad handling when reporting mismatches for byte arrays in Python 3 | |
47 | ||
48 | === Version 1.8.2 === | |
49 | ||
50 | * [Bug] Fix unicode syntax via u() introduction (puppsman) | |
51 | ||
52 | === Version 1.8.1 === | |
53 | ||
54 | * Added not_ alias for is_not [Matteo Bertini] | |
55 | * Added doc directory to the sdist [Alex Brandt] | |
56 | ||
57 | === Version 1.8 == | |
58 | ||
59 | * Supported versions | |
60 | - Support for Python 2.5 and Jython 2.5 has been dropped. They may still work, but no promises. | |
61 | ||
62 | * Bug Fixes | |
63 | - [#39] is_empty was missing from the global namespace | |
64 | ||
65 | * New Features | |
66 | - Support for numpy numeric values in iscloseto (Alexander Beedie) | |
67 | - A matcher targeting exceptions and call results (Per Fagrell) | |
68 | ||
69 | === Version 1.7 == | |
70 | ||
71 | 2 Sep 2013 (Version 1.7.2) | |
72 | * Supported versions | |
73 | - As of this version, support for Python 3.1 has been dropped due to no available CI platform. | |
74 | - Added support for Python 3.3 | |
75 | ||
76 | * Bug fixes: | |
77 | - string_contains_in_order is now used in the test as it would be in an application, and is properly exported. (Romilly Cocking) | |
78 | - Fix mismatch description of containing_inanyorder (David Keijser) | |
79 | - added import of stringmatches to text/__init__.py (Eric Scheidemantle) | |
80 | - added matches_regexp to __all__ list to library/__init__.py (Eric Scheidemantle) | |
81 | ||
82 | 5 Jan 2010 (Version 1.7.1) | |
83 | * Bug fixes: | |
84 | - included a fix by jaimegildesagredo for issue #28 (has_properties was not importable) | |
85 | - included a fix by keys for contains_inanyorder | |
86 | ||
87 | 29 Dec 2012 | |
88 | (All changes by Chris Rose unless otherwise noted.) | |
89 | ||
90 | * New matchers: | |
91 | - matches_regexp matches a regular expression in a string. | |
92 | - has_properties matches an object with more than one property. | |
93 | - is_empty matches any object with length 0. | |
94 | ||
95 | * Improvements: | |
96 | - Can now do matching against old-style classes. | |
97 | - Sequence matchers handle generators, as well as actual sequences and | |
98 | pseudo-sequences. | |
99 | - README enhancements by ming13 | |
100 | ||
101 | ||
102 | === Version 1.6 == | |
103 | ||
104 | 27 Sep 2011 | |
105 | (All changes by Chris Rose unless otherwise noted.) | |
106 | ||
107 | * Packaging: | |
108 | - Python 3.2 support. | |
109 | ||
110 | * New matchers: | |
111 | - has_property('property_name', value_matcher) matches if object has a property with a given name whose value satisfies a given matcher. | |
112 | ||
113 | * Improvements: | |
114 | - hasEntries supports two new calling conventions: | |
115 | has_entries({'key' : value_matcher, 'key_2' : other_value_matcher}) | |
116 | has_entries(key=value_matcher, key_2=other_value_matcher) | |
117 | - Describe Unicode strings by their __repr__. Thanks to: Sebastian Arming | |
118 | - Rewrote documentation. (Jon Reid) | |
119 | ||
120 | ||
121 | == Version 1.5 == | |
122 | ||
123 | 29 Apr 2011 | |
124 | * Packaging: | |
125 | - Python 3.1 support. Thanks to: Chris Rose | |
126 | - Easier installation with bootstrapping. Thanks to: Chris Rose | |
127 | ||
128 | * Mock integration: | |
129 | - "match_equality" wraps a matcher to define equality in terms of satisfying the matcher. This allows Hamcrest matchers to be used in libraries that are not Hamcrest-aware, such as Michael Foord's mock library. Thanks to: Chris Rose | |
130 | ||
131 | * New matcher: | |
132 | - "string_contains_in_order" matches string containing given list of substrings, in order. Thanks to: Romilly Cocking | |
133 | ||
134 | * Improved matchers: | |
135 | - For consistency, changed "any_of" and "all_of" to implicitly wrap non-matcher values in EqualTo. Thanks to: Chris Rose | |
136 | - Changed "sameInstance" mismatch description to omit address when describing | |
137 | None. | |
138 | ||
139 | ||
140 | == Version 1.4 == | |
141 | ||
142 | 13 Feb 2011 | |
143 | * New matchers: | |
144 | - "has_entries" matches dictionary containing key-value pairs satisfying a given list of alternating keys and value matchers. | |
145 | ||
146 | * "assert_that" can be invoked with a single boolean argument; the reason message is now optional. This is a convenience replacement for assertTrue. Thanks to: Jeong-Min Lee | |
147 | ||
148 | * Improved descriptions: | |
149 | - Reverted 1.3 change: Describe None as "<None>" after all, since it is an object. | |
150 | - "is_" no longer says "is ..." in its description, but just lets the inner description pass through. | |
151 | - Consistently use articles to begin descriptions, such as "a sequence containing" instead of "sequence containing". | |
152 | ||
153 | ||
154 | == Version 1.3 == | |
155 | ||
156 | 04 Feb 2011 | |
157 | * PyHamcrest is now compatible with Python 3! To install PyHamcrest on Python 3: | |
158 | - Install the "distribute" package, http://pypi.python.org/pypi/distribute | |
159 | - Run "python3 setup.py install" | |
160 | Unit tests are not converted by the install procedure. Run "2to3 -nw ." separately to convert them. You may discover import statements in the __init__.py files (and one in core/base_description.py) that need dot prefixes. | |
161 | Thanks to: Jeong-Min Lee | |
162 | ||
163 | * Improved descriptions and mismatch descriptions of several matchers, including: | |
164 | - Fixed "contains" and "contains_inanyorder" to describe mismatch if item is not a sequence. | |
165 | - Fixed "described_as" to use nested matcher to generate mismatch description. | |
166 | - "same_instance" is more readable, and includes object memory addresses. | |
167 | - If object has a length, "has_length" mismatch describes actual length. | |
168 | - Describe None as "None" instead of "<None>". | |
169 | - Don't wrap angle brackets around a description that already has them. | |
170 | - Improved readability of several matchers. | |
171 | ||
172 | ||
173 | == Version 1.2.1 == | |
174 | ||
175 | 04 Jan 2011 | |
176 | * Fixed "assert_that" to describe the diagnosis of the mismatch, not just the | |
177 | mismatched value. PyHamcrest will now give even more useful information. | |
178 | ||
179 | * Expanded BaseDescription.append_description_of to handle all types of values, not just self-describing values. | |
180 | ||
181 | * Deprecated: | |
182 | - Description.append_value no longer needed; call append_description_of instead. | |
183 | - BaseDescription.append_value_list no longer needed; call append_list instead. | |
184 | - SelfDescribingValue no longer needed. | |
185 | ||
186 | 1.2.1 fixes to 1.2: | |
187 | - Corrected manifest so install works. Thanks to: Jeong-Min Lee | |
188 | ||
189 | ||
190 | == Version 1.1 == | |
191 | ||
192 | 28 Dec 2010 | |
193 | * New matchers: | |
194 | - "contains" matches sequence containing matching items in order. | |
195 | - "contains_inanyorder" matches sequence containing matching items in any order. | |
196 | ||
197 | * Added Sphinx documentation support. | |
198 | ||
199 | ||
200 | == Version 1.0 == | |
201 | ||
202 | 04 Dec 2010 | |
203 | * First official release | |
204 | * Text matchers now support Unicode strings | |
205 | ||
206 | 15 Jan 2008 | |
207 | * Initial submission |
0 | include CHANGES.txt | |
1 | include LICENSE.txt | |
2 | include README.md | |
0 | include LICENSE.txt *.rst *.md *.toml *.yml *.yaml *.ini | |
1 | include requirements* | |
2 | graft .github | |
3 | ||
4 | # Tests | |
5 | include tox.ini conftest.py | |
6 | recursive-include tests *.py | |
7 | recursive-include tests *.yml | |
8 | ||
9 | # Documentation | |
10 | include doc/Makefile doc/docutils.conf | |
3 | 11 | recursive-include examples *.py |
4 | recursive-include doc * | |
12 | recursive-include doc *.png | |
13 | recursive-include doc *.svg | |
14 | recursive-include doc *.py | |
15 | recursive-include doc *.rst | |
16 | prune doc/_build | |
17 | ||
18 | # remove some of the random source | |
19 | prune docker | |
20 | exclude release.sh | |
21 | ||
22 | # Just to keep check-manifest happy; on releases those files are gone. | |
23 | # Last rule wins! | |
24 | exclude changelog.d/*.rst | |
25 | include changelog.d/towncrier_template.rst |
0 | 0 | PyHamcrest |
1 | 1 | ========== |
2 | 2 | |
3 | | |docs| |travis| |coveralls| |landscape| |scrutinizer| | |
4 | | |version| |downloads| |wheel| |supported-versions| |supported-implementations| | |
5 | | |GitHub forks| |GitHub stars| |GitHub watchers| |GitHub contributors| |Lines of Code| | |
6 | | |GitHub issues| |GitHub issues-closed| |GitHub pull-requests| |GitHub pull-requests closed| | |
7 | ||
8 | .. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/ | |
9 | :target: https://pyhamcrest.readthedocs.org/ | |
3 | | |docs| |status| |version| |downloads| | |
4 | ||
5 | .. |docs| image:: https://readthedocs.org/projects/pyhamcrest/badge/?version=latest | |
6 | :target: https://pyhamcrest.readthedocs.io/en/latest/?badge=latest | |
10 | 7 | :alt: Documentation Status |
11 | 8 | |
12 | .. |travis| image:: http://img.shields.io/travis/hamcrest/PyHamcrest/master.svg | |
13 | :alt: Travis-CI Build Status | |
14 | :target: https://travis-ci.org/hamcrest/PyHamcrest | |
15 | ||
16 | .. |appveyor| image:: https://ci.appveyor.com/api/projects/status/github/hamcrest/PyHamcrest?branch=master&svg=true | |
17 | :alt: AppVeyor Build Status | |
18 | :target: https://ci.appveyor.com/project/hamcrest/PyHamcrest | |
19 | ||
20 | .. |coveralls| image:: http://img.shields.io/coveralls/hamcrest/PyHamcrest/master.svg?style=flat | |
21 | :alt: Coverage Status | |
22 | :target: https://coveralls.io/r/hamcrest/PyHamcrest | |
23 | ||
24 | .. |landscape| image:: https://landscape.io/github/hamcrest/PyHamcrest/master/landscape.svg?style=flat | |
25 | :target: https://landscape.io/github/hamcrest/PyHamcrest/master | |
26 | :alt: Code Quality Status | |
9 | .. |status| image:: https://github.com/hamcrest/PyHamcrest/workflows/CI/badge.svg | |
10 | :alt: CI Build Status | |
11 | :target: https://github.com/hamcrest/PyHamcrest/actions?query=workflow%3ACI | |
27 | 12 | |
28 | 13 | .. |version| image:: http://img.shields.io/pypi/v/PyHamcrest.svg?style=flat |
29 | 14 | :alt: PyPI Package latest release |
32 | 17 | .. |downloads| image:: http://img.shields.io/pypi/dm/PyHamcrest.svg?style=flat |
33 | 18 | :alt: PyPI Package monthly downloads |
34 | 19 | :target: https://pypi.python.org/pypi/PyHamcrest |
35 | ||
36 | .. |wheel| image:: https://pypip.in/wheel/PyHamcrest/badge.svg?style=flat | |
37 | :alt: PyPI Wheel | |
38 | :target: https://pypi.python.org/pypi/PyHamcrest | |
39 | ||
40 | .. |supported-versions| image:: https://pypip.in/py_versions/PyHamcrest/badge.svg?style=flat | |
41 | :alt: Supported versions | |
42 | :target: https://pypi.python.org/pypi/PyHamcrest | |
43 | ||
44 | .. |GitHub forks| image:: https://img.shields.io/github/forks/hamcrest/PyHamcrest.svg?label=Fork&logo=github | |
45 | :alt: GitHub forks | |
46 | :target: https://github.com/hamcrest/PyHamcrest/network/members | |
47 | ||
48 | .. |GitHub stars| image:: https://img.shields.io/github/stars/hamcrest/PyHamcrest.svg?label=Star&logo=github | |
49 | :alt: GitHub stars | |
50 | :target: https://github.com/hamcrest/PyHamcrest/stargazers/ | |
51 | ||
52 | .. |GitHub watchers| image:: https://img.shields.io/github/watchers/hamcrest/PyHamcrest.svg?label=Watch&logo=github | |
53 | :alt: GitHub watchers | |
54 | :target: https://github.com/hamcrest/PyHamcrest/watchers/ | |
55 | ||
56 | .. |GitHub contributors| image:: https://img.shields.io/github/contributors/hamcrest/PyHamcrest.svg?logo=github | |
57 | :alt: GitHub contributors | |
58 | :target: https://github.com/hamcrest/PyHamcrest/graphs/contributors/ | |
59 | ||
60 | .. |GitHub issues| image:: https://img.shields.io/github/issues/hamcrest/PyHamcrest.svg?logo=github | |
61 | :alt: GitHub issues | |
62 | :target: https://github.com/hamcrest/PyHamcrest/issues/ | |
63 | ||
64 | .. |GitHub issues-closed| image:: https://img.shields.io/github/issues-closed/hamcrest/PyHamcrest.svg?logo=github | |
65 | :alt: GitHub issues-closed | |
66 | :target: https://github.com/hamcrest/PyHamcrest/issues?q=is%3Aissue+is%3Aclosed | |
67 | ||
68 | .. |GitHub pull-requests| image:: https://img.shields.io/github/issues-pr/hamcrest/PyHamcrest.svg?logo=github | |
69 | :alt: GitHub pull-requests | |
70 | :target: https://github.com/hamcrest/PyHamcrest/pulls | |
71 | ||
72 | .. |GitHub pull-requests closed| image:: https://img.shields.io/github/issues-pr-closed/hamcrest/PyHamcrest.svg?logo=github | |
73 | :alt: GitHub pull-requests closed | |
74 | :target: https://github.com/hamcrest/PyHamcrest/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aclosed | |
75 | ||
76 | .. |Lines of Code| image:: https://tokei.rs/b1/github/hamcrest/PyHamcrest | |
77 | :alt: Lines of Code | |
78 | :target: https://github.com/hamcrest/PyHamcrest | |
79 | ||
80 | .. |supported-implementations| image:: https://pypip.in/implementation/PyHamcrest/badge.svg?style=flat | |
81 | :alt: Supported implementations | |
82 | :target: https://pypi.python.org/pypi/PyHamcrest | |
83 | ||
84 | .. |scrutinizer| image:: https://img.shields.io/scrutinizer/g/hamcrest/PyHamcrest/master.svg?style=flat | |
85 | :alt: Scrtinizer Status | |
86 | :target: https://scrutinizer-ci.com/g/hamcrest/PyHamcrest/ | |
87 | 20 | |
88 | 21 | |
89 | 22 | Introduction |
124 | 57 | from hamcrest import * |
125 | 58 | import unittest |
126 | 59 | |
60 | ||
127 | 61 | class BiscuitTest(unittest.TestCase): |
128 | 62 | def testEquals(self): |
129 | theBiscuit = Biscuit('Ginger') | |
130 | myBiscuit = Biscuit('Ginger') | |
63 | theBiscuit = Biscuit("Ginger") | |
64 | myBiscuit = Biscuit("Ginger") | |
131 | 65 | assert_that(theBiscuit, equal_to(myBiscuit)) |
132 | 66 | |
133 | if __name__ == '__main__': | |
67 | ||
68 | if __name__ == "__main__": | |
134 | 69 | unittest.main() |
135 | 70 | |
136 | 71 | The ``assert_that`` function is a stylized sentence for making a test |
145 | 80 | |
146 | 81 | .. code:: python |
147 | 82 | |
148 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), 'chocolate chips') | |
149 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), 'hazelnuts') | |
83 | assert_that(theBiscuit.getChocolateChipCount(), equal_to(10), "chocolate chips") | |
84 | assert_that(theBiscuit.getHazelnutCount(), equal_to(3), "hazelnuts") | |
150 | 85 | |
151 | 86 | As a convenience, assert_that can also be used to verify a boolean condition: |
152 | 87 | |
153 | 88 | .. code:: python |
154 | 89 | |
155 | assert_that(theBiscuit.isCooked(), 'cooked') | |
90 | assert_that(theBiscuit.isCooked(), "cooked") | |
156 | 91 | |
157 | 92 | This is equivalent to the ``assert_`` method of unittest.TestCase, but because |
158 | 93 | it's a standalone function, it offers greater flexibility in test writing. |
281 | 216 | from hamcrest.core.base_matcher import BaseMatcher |
282 | 217 | from hamcrest.core.helpers.hasmethod import hasmethod |
283 | 218 | |
219 | ||
284 | 220 | class IsGivenDayOfWeek(BaseMatcher): |
285 | ||
286 | 221 | def __init__(self, day): |
287 | 222 | self.day = day # Monday is 0, Sunday is 6 |
288 | 223 | |
289 | 224 | def _matches(self, item): |
290 | if not hasmethod(item, 'weekday'): | |
225 | if not hasmethod(item, "weekday"): | |
291 | 226 | return False |
292 | 227 | return item.weekday() == self.day |
293 | 228 | |
294 | 229 | def describe_to(self, description): |
295 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
296 | 'Friday', 'Saturday', 'Sunday'] | |
297 | description.append_text('calendar date falling on ') \ | |
298 | .append_text(day_as_string[self.day]) | |
230 | day_as_string = [ | |
231 | "Monday", | |
232 | "Tuesday", | |
233 | "Wednesday", | |
234 | "Thursday", | |
235 | "Friday", | |
236 | "Saturday", | |
237 | "Sunday", | |
238 | ] | |
239 | description.append_text("calendar date falling on ").append_text( | |
240 | day_as_string[self.day] | |
241 | ) | |
242 | ||
299 | 243 | |
300 | 244 | def on_a_saturday(): |
301 | 245 | return IsGivenDayOfWeek(5) |
325 | 269 | import unittest |
326 | 270 | from isgivendayofweek import on_a_saturday |
327 | 271 | |
272 | ||
328 | 273 | class DateTest(unittest.TestCase): |
329 | 274 | def testDateIsOnASaturday(self): |
330 | 275 | d = datetime.date(2008, 4, 26) |
331 | 276 | assert_that(d, is_(on_a_saturday())) |
332 | 277 | |
333 | if __name__ == '__main__': | |
278 | ||
279 | if __name__ == "__main__": | |
334 | 280 | unittest.main() |
335 | 281 | |
336 | 282 | Even though the ``on_a_saturday`` function creates a new matcher each time it |
0 | {% for section, _ in sections.items() %} {% set underline = underlines[0] %}{% if section %}{{section}} {{ underline * section|length }}{% set underline = underlines[1] %} | |
1 | ||
2 | {% endif %} | |
3 | ||
4 | {% if sections[section] %} {% for category, val in definitions.items() if category in sections[section]%} {{ definitions[category]['name'] }} {{ underline * definitions[category]['name']|length }} | |
5 | ||
6 | {% if definitions[category]['showcontent'] %} {% for text, values in sections[section][category].items() %} - {{ text }} | |
7 | ||
8 | {{ values|join(',n ') }} | |
9 | {% endfor %} | |
10 | ||
11 | {% else %} - {{ sections[section][category]['']|join(', ') }} | |
12 | ||
13 | {% endif %} {% if sections[section][category]|length == 0 %} No significant changes. | |
14 | ||
15 | {% else %} {% endif %} | |
16 | ||
17 | {% endfor %} {% else %} No significant changes. | |
18 | ||
19 | {% endif %} {% endfor %} ---- |
11 | 11 | # serve to show the default. |
12 | 12 | |
13 | 13 | import sys, os |
14 | import six | |
15 | import sphinx_rtd_theme | |
14 | import alabaster | |
16 | 15 | |
17 | 16 | # If extensions (or modules to document with autodoc) are in another directory, |
18 | 17 | # add these directories to sys.path here. If the directory is relative to the |
19 | 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. |
20 | sys.path.insert(0, os.path.abspath('..')) | |
19 | sys.path.insert(0, os.path.abspath("../src")) | |
21 | 20 | |
22 | 21 | from hamcrest import __version__ |
23 | 22 | |
24 | 23 | # -- General configuration ----------------------------------------------------- |
25 | 24 | |
26 | 25 | # If your documentation needs a minimal Sphinx version, state it here. |
27 | #needs_sphinx = '1.0' | |
26 | # needs_sphinx = '1.0' | |
28 | 27 | |
29 | 28 | # Add any Sphinx extension module names here, as strings. They can be extensions |
30 | 29 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. |
31 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx'] | |
32 | ||
33 | autodoc_default_options = {'members': None, 'show-inheritance': None} | |
34 | intersphinx_mapping = {'python': ('http://docs.python.org/2.6', None)} | |
30 | extensions = ["sphinx.ext.autodoc", "sphinx.ext.intersphinx", "alabaster"] | |
31 | ||
32 | autodoc_default_options = {"members": None, "show-inheritance": None} | |
33 | autodoc_typehints = "description" | |
34 | intersphinx_mapping = {"python": ("http://docs.python.org/3", None)} | |
35 | 35 | |
36 | 36 | # Add any paths that contain templates here, relative to this directory. |
37 | templates_path = ['_templates'] | |
37 | templates_path = ["_templates"] | |
38 | 38 | |
39 | 39 | # The suffix of source filenames. |
40 | source_suffix = '.rst' | |
40 | source_suffix = ".rst" | |
41 | 41 | |
42 | 42 | # The encoding of source files. |
43 | #source_encoding = 'utf-8-sig' | |
43 | # source_encoding = 'utf-8-sig' | |
44 | 44 | |
45 | 45 | # The master toctree document. |
46 | master_doc = 'index' | |
46 | master_doc = "index" | |
47 | 47 | |
48 | 48 | # General information about the project. |
49 | project = six.u('PyHamcrest') | |
50 | copyright = six.u('2020, hamcrest.org') | |
49 | project = "PyHamcrest" | |
50 | copyright = "2020, hamcrest.org" | |
51 | 51 | |
52 | 52 | # The version info for the project you're documenting, acts as replacement for |
53 | 53 | # |version| and |release|, also used in various other places throughout the |
54 | 54 | # built documents. |
55 | 55 | # |
56 | # The full version, including alpha/beta/rc tags. | |
57 | version = __version__ | |
58 | ||
56 | 59 | # The short X.Y version. |
57 | version = __version__ | |
58 | # The full version, including alpha/beta/rc tags. | |
59 | release = __version__ | |
60 | release = ".".join(version.split(".")[:2]) | |
60 | 61 | |
61 | 62 | # The language for content autogenerated by Sphinx. Refer to documentation |
62 | 63 | # for a list of supported languages. |
63 | #language = None | |
64 | # language = None | |
64 | 65 | |
65 | 66 | # There are two options for replacing |today|: either, you set today to some |
66 | 67 | # non-false value, then it is used: |
67 | #today = '' | |
68 | # today = '' | |
68 | 69 | # Else, today_fmt is used as the format for a strftime call. |
69 | #today_fmt = '%B %d, %Y' | |
70 | # today_fmt = '%B %d, %Y' | |
70 | 71 | |
71 | 72 | # List of patterns, relative to source directory, that match files and |
72 | 73 | # directories to ignore when looking for source files. |
73 | exclude_patterns = ['_build'] | |
74 | exclude_patterns = ["_build"] | |
74 | 75 | |
75 | 76 | # The reST default role (used for this markup: `text`) to use for all documents. |
76 | default_role = 'py:obj' | |
77 | default_role = "py:obj" | |
77 | 78 | |
78 | 79 | # If true, '()' will be appended to :func: etc. cross-reference text. |
79 | 80 | add_function_parentheses = False |
80 | 81 | |
81 | 82 | # If true, the current module name will be prepended to all description |
82 | 83 | # unit titles (such as .. function::). |
83 | #add_module_names = True | |
84 | # add_module_names = True | |
84 | 85 | |
85 | 86 | # If true, sectionauthor and moduleauthor directives will be shown in the |
86 | 87 | # output. They are ignored by default. |
87 | #show_authors = False | |
88 | # show_authors = False | |
88 | 89 | |
89 | 90 | # The name of the Pygments (syntax highlighting) style to use. |
90 | pygments_style = 'sphinx' | |
91 | pygments_style = "sphinx" | |
91 | 92 | |
92 | 93 | # A list of ignored prefixes for module index sorting. |
93 | #modindex_common_prefix = [] | |
94 | # modindex_common_prefix = [] | |
94 | 95 | |
95 | 96 | |
96 | 97 | # -- Options for HTML output --------------------------------------------------- |
97 | 98 | |
98 | 99 | # The theme to use for HTML and HTML Help pages. See the documentation for |
99 | 100 | # a list of builtin themes. |
100 | html_theme = 'sphinx_rtd_theme' | |
101 | html_theme = "alabaster" | |
101 | 102 | |
102 | 103 | # Theme options are theme-specific and customize the look and feel of a theme |
103 | 104 | # further. For a list of options available for each theme, see the |
104 | 105 | # documentation. |
105 | #html_theme_options = {} | |
106 | # html_theme_options = {} | |
106 | 107 | |
107 | 108 | # Add any paths that contain custom themes here, relative to this directory. |
108 | #html_theme_path = [] | |
109 | html_theme_path = [ sphinx_rtd_theme.get_html_theme_path() ] | |
109 | # html_theme_path = [] | |
110 | html_theme_path = [alabaster.get_path()] | |
110 | 111 | |
111 | 112 | # The name for this set of Sphinx documents. If None, it defaults to |
112 | 113 | # "<project> v<release> documentation". |
113 | #html_title = None | |
114 | # html_title = None | |
114 | 115 | |
115 | 116 | # A shorter title for the navigation bar. Default is the same as html_title. |
116 | #html_short_title = None | |
117 | # html_short_title = None | |
117 | 118 | |
118 | 119 | # The name of an image file (relative to this directory) to place at the top |
119 | 120 | # of the sidebar. |
120 | #html_logo = None | |
121 | # html_logo = None | |
121 | 122 | |
122 | 123 | # The name of an image file (within the static path) to use as favicon of the |
123 | 124 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 |
124 | 125 | # pixels large. |
125 | #html_favicon = None | |
126 | # html_favicon = None | |
126 | 127 | |
127 | 128 | # Add any paths that contain custom static files (such as style sheets) here, |
128 | 129 | # relative to this directory. They are copied after the builtin static files, |
131 | 132 | |
132 | 133 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, |
133 | 134 | # using the given strftime format. |
134 | #html_last_updated_fmt = '%b %d, %Y' | |
135 | # html_last_updated_fmt = '%b %d, %Y' | |
135 | 136 | |
136 | 137 | # If true, SmartyPants will be used to convert quotes and dashes to |
137 | 138 | # typographically correct entities. |
138 | #html_use_smartypants = True | |
139 | # html_use_smartypants = True | |
139 | 140 | |
140 | 141 | # Custom sidebar templates, maps document names to template names. |
141 | #html_sidebars = {} | |
142 | # html_sidebars = {} | |
142 | 143 | |
143 | 144 | # Additional templates that should be rendered to pages, maps page names to |
144 | 145 | # template names. |
145 | #html_additional_pages = {} | |
146 | # html_additional_pages = {} | |
146 | 147 | |
147 | 148 | # If false, no module index is generated. |
148 | #html_domain_indices = True | |
149 | # html_domain_indices = True | |
149 | 150 | |
150 | 151 | # If false, no index is generated. |
151 | #html_use_index = True | |
152 | # html_use_index = True | |
152 | 153 | |
153 | 154 | # If true, the index is split into individual pages for each letter. |
154 | #html_split_index = False | |
155 | # html_split_index = False | |
155 | 156 | |
156 | 157 | # If true, links to the reST sources are added to the pages. |
157 | #html_show_sourcelink = True | |
158 | # html_show_sourcelink = True | |
158 | 159 | |
159 | 160 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. |
160 | #html_show_sphinx = True | |
161 | # html_show_sphinx = True | |
161 | 162 | |
162 | 163 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. |
163 | #html_show_copyright = True | |
164 | # html_show_copyright = True | |
164 | 165 | |
165 | 166 | # If true, an OpenSearch description file will be output, and all pages will |
166 | 167 | # contain a <link> tag referring to it. The value of this option must be the |
167 | 168 | # base URL from which the finished HTML is served. |
168 | #html_use_opensearch = '' | |
169 | # html_use_opensearch = '' | |
169 | 170 | |
170 | 171 | # This is the file name suffix for HTML files (e.g. ".xhtml"). |
171 | #html_file_suffix = None | |
172 | # html_file_suffix = None | |
172 | 173 | |
173 | 174 | # Output file base name for HTML help builder. |
174 | htmlhelp_basename = 'PyHamcrestdoc' | |
175 | htmlhelp_basename = "PyHamcrestdoc" | |
175 | 176 | |
176 | 177 | |
177 | 178 | # -- Options for LaTeX output -------------------------------------------------- |
178 | 179 | |
179 | 180 | # The paper size ('letter' or 'a4'). |
180 | #latex_paper_size = 'letter' | |
181 | # latex_paper_size = 'letter' | |
181 | 182 | |
182 | 183 | # The font size ('10pt', '11pt' or '12pt'). |
183 | #latex_font_size = '10pt' | |
184 | # latex_font_size = '10pt' | |
184 | 185 | |
185 | 186 | # Grouping the document tree into LaTeX files. List of tuples |
186 | 187 | # (source start file, target name, title, author, documentclass [howto/manual]). |
187 | 188 | latex_documents = [ |
188 | ('index', 'PyHamcrest.tex', six.u('PyHamcrest Documentation'), | |
189 | six.u('hamcrest.org'), 'manual'), | |
189 | ("index", "PyHamcrest.tex", "PyHamcrest Documentation", "hamcrest.org"), | |
190 | "manual", | |
190 | 191 | ] |
191 | 192 | |
192 | 193 | # The name of an image file (relative to this directory) to place at the top of |
193 | 194 | # the title page. |
194 | #latex_logo = None | |
195 | # latex_logo = None | |
195 | 196 | |
196 | 197 | # For "manual" documents, if this is true, then toplevel headings are parts, |
197 | 198 | # not chapters. |
198 | #latex_use_parts = False | |
199 | # latex_use_parts = False | |
199 | 200 | |
200 | 201 | # If true, show page references after internal links. |
201 | #latex_show_pagerefs = False | |
202 | # latex_show_pagerefs = False | |
202 | 203 | |
203 | 204 | # If true, show URL addresses after external links. |
204 | #latex_show_urls = False | |
205 | # latex_show_urls = False | |
205 | 206 | |
206 | 207 | # Additional stuff for the LaTeX preamble. |
207 | #latex_preamble = '' | |
208 | # latex_preamble = '' | |
208 | 209 | |
209 | 210 | # Documents to append as an appendix to all manuals. |
210 | #latex_appendices = [] | |
211 | # latex_appendices = [] | |
211 | 212 | |
212 | 213 | # If false, no module index is generated. |
213 | #latex_domain_indices = True | |
214 | # latex_domain_indices = True | |
214 | 215 | |
215 | 216 | # PyHamcrest customization: Don't skip BaseMatcher's _matches method |
216 | 217 | def skip_member(app, what, name, obj, skip, options): |
217 | if skip and str(obj).find('BaseMatcher._matches') >= 0: | |
218 | if skip and str(obj).find("BaseMatcher._matches") >= 0: | |
218 | 219 | return False |
219 | 220 | return skip |
220 | 221 | |
222 | ||
221 | 223 | def setup(app): |
222 | app.connect('autodoc-skip-member', skip_member) | |
224 | app.connect("autodoc-skip-member", skip_member) | |
225 | ||
223 | 226 | |
224 | 227 | # -- Options for manual page output -------------------------------------------- |
225 | 228 | |
226 | 229 | # One entry per manual page. List of tuples |
227 | 230 | # (source start file, name, description, authors, manual section). |
228 | man_pages = [ | |
229 | ('index', 'pyhamcrest', six.u('PyHamcrest Documentation'), | |
230 | [six.u('hamcrest.org')], 1) | |
231 | ] | |
231 | man_pages = [("index", "pyhamcrest", "PyHamcrest Documentation", ["hamcrest.org"], 1)] |
0 | 0 | import sys |
1 | sys.path.append('..') | |
1 | ||
2 | sys.path.append("..") | |
2 | 3 | |
3 | 4 | from hamcrest.core.base_matcher import BaseMatcher |
4 | 5 | from hamcrest.core.helpers.hasmethod import hasmethod |
16 | 17 | |
17 | 18 | def _matches(self, item): |
18 | 19 | """Test whether item matches.""" |
19 | if not hasmethod(item, 'weekday'): | |
20 | if not hasmethod(item, "weekday"): | |
20 | 21 | return False |
21 | 22 | return item.weekday() == self.day |
22 | 23 | |
23 | 24 | def describe_to(self, description): |
24 | 25 | """Describe the matcher.""" |
25 | day_as_string = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', | |
26 | 'Friday', 'Saturday', 'Sunday'] | |
27 | description.append_text('calendar date falling on ') \ | |
28 | .append_text(day_as_string[self.day]) | |
26 | day_as_string = [ | |
27 | "Monday", | |
28 | "Tuesday", | |
29 | "Wednesday", | |
30 | "Thursday", | |
31 | "Friday", | |
32 | "Saturday", | |
33 | "Sunday", | |
34 | ] | |
35 | description.append_text("calendar date falling on ").append_text(day_as_string[self.day]) | |
29 | 36 | |
30 | 37 | |
31 | 38 | def on_a_saturday(): |
36 | 43 | class SampleTest(unittest.TestCase): |
37 | 44 | def testDateIsOnASaturday(self): |
38 | 45 | """Example of successful match.""" |
39 | d = datetime.date(2008, 04, 26) | |
46 | d = datetime.date(2008, 4, 26) | |
40 | 47 | assert_that(d, is_(on_a_saturday())) |
41 | 48 | |
42 | 49 | def testFailsWithMismatchedDate(self): |
43 | 50 | """Example of what happens with date that doesn't match.""" |
44 | d = datetime.date(2008, 04, 06) | |
51 | d = datetime.date(2008, 4, 6) | |
45 | 52 | assert_that(d, is_(on_a_saturday())) |
46 | 53 | |
47 | 54 | def testFailsWithNonDate(self): |
48 | 55 | """Example of what happens with object that isn't a date.""" |
49 | d = 'oops' | |
56 | d = "oops" | |
50 | 57 | assert_that(d, is_(on_a_saturday())) |
51 | 58 | |
52 | 59 | |
53 | if __name__ == '__main__': | |
60 | if __name__ == "__main__": | |
54 | 61 | unittest.main() |
0 | 0 | import sys |
1 | sys.path.append('..') | |
1 | ||
2 | sys.path.append("..") | |
2 | 3 | |
3 | 4 | from hamcrest import * |
4 | 5 | import unittest |
6 | 7 | |
7 | 8 | class ExampleWithAssertThat(unittest.TestCase): |
8 | 9 | def testUsingAssertThat(self): |
9 | assert_that('xx', is_('xx')) | |
10 | assert_that('yy', is_not('xx')) | |
11 | assert_that('i like cheese', contains_string('cheese')) | |
10 | assert_that("xx", is_("xx")) | |
11 | assert_that("yy", is_not("xx")) | |
12 | assert_that("i like cheese", contains_string("cheese")) | |
12 | 13 | |
13 | 14 | def testCanAlsoSupplyDescriptiveReason(self): |
14 | assert_that('xx', is_('xx'), 'description') | |
15 | assert_that("xx", is_("xx"), "description") | |
15 | 16 | |
16 | 17 | def testCanAlsoAssertPlainBooleans(self): |
17 | assert_that(True, 'This had better not fail') | |
18 | assert_that(True, "This had better not fail") | |
18 | 19 | |
19 | 20 | |
20 | if __name__ == '__main__': | |
21 | if __name__ == "__main__": | |
21 | 22 | unittest.main() |
0 | [build-system] | |
1 | requires = ["setuptools>=40.6.0", "wheel"] | |
2 | build-backend = "setuptools.build_meta" | |
3 | ||
4 | ||
5 | [tool.coverage.run] | |
6 | parallel = true | |
7 | branch = true | |
8 | source = ["hamcrest"] | |
9 | ||
10 | [tool.coverage.paths] | |
11 | source = ["src", ".tox/*/site-packages"] | |
12 | ||
13 | [tool.coverage.report] | |
14 | show_missing = true | |
15 | skip_covered = true | |
16 | exclude_lines = [ | |
17 | # a more strict default pragma | |
18 | "\\# pragma: no cover\\b", | |
19 | ||
20 | # allow defensive code | |
21 | "^\\s*raise AssertionError\\b", | |
22 | "^\\s*raise NotImplementedError\\b", | |
23 | "^\\s*return NotImplemented\\b", | |
24 | "^\\s*raise$", | |
25 | ||
26 | # typing-related code | |
27 | "^if (False|TYPE_CHECKING):", | |
28 | ": \\.\\.\\.(\\s*#.*)?$", | |
29 | "^ +\\.\\.\\.$", | |
30 | "-> ['\"]?NoReturn['\"]?:", | |
31 | ] | |
32 | [tool.black] | |
33 | line_length = 100 | |
34 | ||
35 | [tool.interrogate] | |
36 | verbose = 2 | |
37 | fail-under = 100 | |
38 | whitelist-regex = ["test_.*"] | |
39 | ||
40 | ||
41 | [tool.isort] | |
42 | profile = "hamcrests" | |
43 | ||
44 | known_first_party = "hamcrest" | |
45 | known_third_party = ["hypothesis", "pytest", "setuptools", "six"] | |
46 | ||
47 | ||
48 | [tool.towncrier] | |
49 | package = "hamcrest" | |
50 | package_dir = "src" | |
51 | filename = "CHANGELOG.rst" | |
52 | template = "changelog.d/towncrier_template.rst" | |
53 | issue_format = "`#{issue} <https://github.com/hamcrest/PyHamcrest/issues/{issue}>`_" | |
54 | directory = "changelog.d" | |
55 | title_format = "{version} ({project_date})" | |
56 | underlines = ["-", "^"] |
16 | 16 | # On Python 3, we can't "from hamcrest import __version__" (get ImportError), |
17 | 17 | # so we extract the variable assignment and execute it ourselves. |
18 | 18 | fh = open("src/hamcrest/__init__.py") |
19 | ||
20 | # this will be overridden | |
21 | __version__ = None | |
19 | 22 | try: |
20 | 23 | for line in fh: |
21 | 24 | if re.match("__version__.*", line): |
22 | 25 | exec(line) |
26 | ||
23 | 27 | finally: |
24 | 28 | if fh: |
25 | 29 | fh.close() |
30 | ||
31 | assert __version__ is not None | |
32 | ||
33 | REQUIREMENTS_DOCS = ["sphinx~=3.0", "alabaster~=0.7"] | |
34 | TESTS_BASIC = [ | |
35 | "pytest>=5.0", | |
36 | "pytest-sugar", | |
37 | "pytest-xdist", | |
38 | "coverage[toml]", | |
39 | # No point on Pypy thanks to https://github.com/python/typed_ast/issues/111 | |
40 | "pytest-mypy-plugins; platform_python_implementation != 'PyPy'", | |
41 | "types-mock", | |
42 | ] | |
43 | TESTS_NUMPY = ["numpy"] | |
44 | DEV_TOOLS = [ | |
45 | "towncrier", | |
46 | "twine", | |
47 | "pytest-mypy", | |
48 | "flake8", | |
49 | "black", | |
50 | "tox", | |
51 | "tox-pyenv", | |
52 | "tox-asdf", | |
53 | ] | |
54 | ||
26 | 55 | |
27 | 56 | params = dict( |
28 | 57 | name="PyHamcrest", |
41 | 70 | package_data={"hamcrest": ["py.typed"]}, |
42 | 71 | provides=["hamcrest"], |
43 | 72 | long_description=read("README.rst"), |
73 | long_description_content_type="text/x-rst", | |
44 | 74 | python_requires=">=3.5", |
45 | 75 | install_requires=[], |
76 | extras_require={ | |
77 | "docs": REQUIREMENTS_DOCS, | |
78 | "tests": TESTS_BASIC, | |
79 | "tests-numpy": TESTS_BASIC + TESTS_NUMPY, | |
80 | "dev": REQUIREMENTS_DOCS + TESTS_BASIC + DEV_TOOLS, | |
81 | }, | |
46 | 82 | classifiers=[ |
47 | 83 | "Development Status :: 5 - Production/Stable", |
48 | 84 | "Environment :: Console", |
51 | 87 | "Natural Language :: English", |
52 | 88 | "Operating System :: OS Independent", |
53 | 89 | "Programming Language :: Python :: 3", |
54 | "Programming Language :: Python :: 3.5", | |
55 | 90 | "Programming Language :: Python :: 3.6", |
56 | 91 | "Programming Language :: Python :: 3.7", |
57 | 92 | "Programming Language :: Python :: 3.8", |
0 | 0 | from hamcrest.core import * |
1 | 1 | from hamcrest.library import * |
2 | from hamcrest import core, library | |
2 | 3 | |
3 | __version__ = "2.0.2" | |
4 | __version__ = "2.0.3" | |
4 | 5 | __author__ = "Chris Rose" |
5 | 6 | __copyright__ = "Copyright 2020 hamcrest.org" |
6 | 7 | __license__ = "BSD, see License.txt" |
8 | ||
9 | __all__ = [] | |
10 | __all__.extend(core.__all__) | |
11 | __all__.extend(library.__all__) |
3 | 3 | __author__ = "Jon Reid" |
4 | 4 | __copyright__ = "Copyright 2011 hamcrest.org" |
5 | 5 | __license__ = "BSD, see License.txt" |
6 | ||
7 | __all__ = [ | |
8 | "assert_that", | |
9 | "all_of", | |
10 | "any_of", | |
11 | "anything", | |
12 | "calling", | |
13 | "described_as", | |
14 | "equal_to", | |
15 | "instance_of", | |
16 | "is_", | |
17 | "is_not", | |
18 | "none", | |
19 | "not_", | |
20 | "not_none", | |
21 | "raises", | |
22 | "same_instance", | |
23 | ] |
0 | from textwrap import shorten | |
0 | 1 | from typing import Optional, TypeVar |
1 | 2 | |
2 | 3 | from hamcrest.core.description import Description |
24 | 25 | def __str__(self) -> str: |
25 | 26 | return tostring(self) |
26 | 27 | |
28 | def __repr__(self) -> str: | |
29 | """Returns matcher string representation.""" | |
30 | return "<{0}({1})>".format( | |
31 | self.__class__.__name__, shorten(tostring(self), 60, placeholder="...") | |
32 | ) | |
33 | ||
27 | 34 | def _matches(self, item: T) -> bool: |
28 | 35 | raise NotImplementedError("_matches") |
29 | 36 |
14 | 14 | __author__ = "Jon Reid" |
15 | 15 | __copyright__ = "Copyright 2011 hamcrest.org" |
16 | 16 | __license__ = "BSD, see License.txt" |
17 | ||
18 | __all__ = [ | |
19 | "all_of", | |
20 | "any_of", | |
21 | "anything", | |
22 | "calling", | |
23 | "described_as", | |
24 | "equal_to", | |
25 | "instance_of", | |
26 | "is_", | |
27 | "is_not", | |
28 | "none", | |
29 | "not_", | |
30 | "not_none", | |
31 | "raises", | |
32 | "same_instance", | |
33 | ] |
0 | from typing import Optional, Type, TypeVar, Union, overload | |
0 | from typing import Optional, Type, TypeVar, overload, Any | |
1 | 1 | |
2 | 2 | from hamcrest.core.base_matcher import BaseMatcher |
3 | 3 | from hamcrest.core.description import Description |
45 | 45 | |
46 | 46 | |
47 | 47 | @overload |
48 | def is_(x: Type) -> Matcher[object]: | |
48 | def is_(x: Type) -> Matcher[Any]: | |
49 | 49 | ... |
50 | 50 | |
51 | 51 | |
52 | 52 | @overload |
53 | def is_(x: Union[Matcher[T], T]) -> Matcher[T]: | |
53 | def is_(x: Matcher[T]) -> Matcher[T]: | |
54 | ... | |
55 | ||
56 | ||
57 | @overload | |
58 | def is_(x: T) -> Matcher[T]: | |
54 | 59 | ... |
55 | 60 | |
56 | 61 |
10 | 10 | |
11 | 11 | class IsAnything(BaseMatcher[Any]): |
12 | 12 | def __init__(self, description: Optional[str]) -> None: |
13 | self.description = description or "ANYTHING" # type: str | |
13 | self.description: str = description or "ANYTHING" | |
14 | 14 | |
15 | 15 | def _matches(self, item: Any) -> bool: |
16 | 16 | return True |
21 | 21 | self.pattern = pattern |
22 | 22 | self.matcher = matching |
23 | 23 | self.expected = expected |
24 | self.actual = None # type: Optional[BaseException] | |
25 | self.function = None # type: Optional[Callable[..., Any]] | |
24 | self.actual: Optional[BaseException] = None | |
25 | self.function: Optional[Callable[..., Any]] = None | |
26 | 26 | |
27 | 27 | def _matches(self, function: Callable[..., Any]) -> bool: |
28 | 28 | if not callable(function): |
114 | 114 | class DeferredCallable(object): |
115 | 115 | def __init__(self, func: Callable[..., Any]): |
116 | 116 | self.func = func |
117 | self.args = tuple() # type: Tuple[Any, ...] | |
118 | self.kwargs = {} # type: Mapping[str, Any] | |
117 | self.args: Tuple[Any, ...] = tuple() | |
118 | self.kwargs: Mapping[str, Any] = {} | |
119 | 119 | |
120 | 120 | def __call__(self): |
121 | 121 | self.func(*self.args, **self.kwargs) |
0 | from typing import Any, Iterable, Sequence | |
0 | from typing import Any, Iterable | |
1 | 1 | |
2 | 2 | __author__ = "Jon Reid" |
3 | 3 | __copyright__ = "Copyright 2011 hamcrest.org" |
0 | 0 | from typing import Any, List, Type |
1 | 1 | |
2 | MOCKTYPES = [] # type: List[Type] | |
2 | MOCKTYPES: List[Type] = [] | |
3 | 3 | try: |
4 | 4 | from mock import Mock |
5 | 5 |
12 | 12 | __author__ = "Chris Rose" |
13 | 13 | __copyright__ = "Copyright 2013 hamcrest.org" |
14 | 14 | __license__ = "BSD, see License.txt" |
15 | ||
16 | __all__ = [ | |
17 | "contains", | |
18 | "contains_exactly", | |
19 | "contains_inanyorder", | |
20 | "empty", | |
21 | "has_entries", | |
22 | "has_entry", | |
23 | "has_item", | |
24 | "has_items", | |
25 | "has_key", | |
26 | "has_value", | |
27 | "is_in", | |
28 | "only_contains", | |
29 | ] |
0 | from typing import Hashable, Mapping, TypeVar, Union | |
0 | from typing import Hashable, Mapping, MutableMapping, TypeVar, Union | |
1 | 1 | |
2 | 2 | from hamcrest.core.base_matcher import BaseMatcher |
3 | 3 | from hamcrest.core.description import Description |
31 | 31 | self.key_matcher |
32 | 32 | ).append_text(": ").append_description_of(self.value_matcher).append_text("]") |
33 | 33 | |
34 | def describe_mismatch(self, item: Mapping[K, V], mismatch_description: Description) -> None: | |
35 | key_matches = self._matching_keys(item) | |
36 | if len(key_matches) == 1: | |
37 | key, value = key_matches.popitem() | |
38 | mismatch_description.append_text("value for ").append_description_of(key).append_text( | |
39 | " " | |
40 | ) | |
41 | self.value_matcher.describe_mismatch(value, mismatch_description) | |
42 | else: | |
43 | super().describe_mismatch(item, mismatch_description) | |
44 | ||
45 | def describe_match(self, item: Mapping[K, V], match_description: Description) -> None: | |
46 | key_matches = self._matching_keys(item) | |
47 | if len(key_matches) == 1: | |
48 | key, value = key_matches.popitem() | |
49 | match_description.append_text("value for ").append_description_of(key).append_text(" ") | |
50 | self.value_matcher.describe_mismatch(value, match_description) | |
51 | else: | |
52 | super().describe_match(item, match_description) | |
53 | ||
54 | def _matching_keys(self, item): | |
55 | key_matches: MutableMapping[K, V] = {} | |
56 | if hasmethod(item, "items"): | |
57 | for key, value in item.items(): | |
58 | if self.key_matcher.matches(key): | |
59 | key_matches[key] = value | |
60 | return key_matches | |
61 | ||
34 | 62 | |
35 | 63 | def has_entry( |
36 | 64 | key_match: Union[K, Matcher[K]], value_match: Union[V, Matcher[V]] |
29 | 29 | for key, value_matcher in self.value_matchers: |
30 | 30 | |
31 | 31 | try: |
32 | if not key in item: | |
32 | if key not in item: | |
33 | 33 | if mismatch_description: |
34 | 34 | mismatch_description.append_text("no ").append_description_of( |
35 | 35 | key |
38 | 38 | class IsSequenceContainingEvery(BaseMatcher[Sequence[T]]): |
39 | 39 | def __init__(self, *element_matchers: Matcher[T]) -> None: |
40 | 40 | delegates = [cast(Matcher[Sequence[T]], has_item(e)) for e in element_matchers] |
41 | self.matcher = all_of(*delegates) # type: Matcher[Sequence[T]] | |
41 | self.matcher: Matcher[Sequence[T]] = all_of(*delegates) | |
42 | 42 | |
43 | 43 | def _matches(self, item: Sequence[T]) -> bool: |
44 | 44 | try: |
13 | 13 | |
14 | 14 | |
15 | 15 | def isnumeric(value: Any) -> bool: |
16 | """Confirm that 'value' can be treated numerically; duck-test accordingly | |
17 | """ | |
16 | """Confirm that 'value' can be treated numerically; duck-test accordingly""" | |
18 | 17 | if isinstance(value, (float, complex, int)): |
19 | 18 | return True |
20 | 19 | |
23 | 22 | return True |
24 | 23 | except ArithmeticError: |
25 | 24 | return True |
26 | except: | |
25 | except Exception: | |
27 | 26 | return False |
28 | 27 | |
29 | 28 |
0 | 0 | # coding: utf-8 |
1 | import platform | |
1 | 2 | from unittest.mock import sentinel |
2 | 3 | |
3 | 4 | import pytest |
39 | 40 | (Described(), "described"), |
40 | 41 | ("unicode-py3", "'unicode-py3'"), |
41 | 42 | (b"bytes-py3", "<b'bytes-py3'>"), |
42 | ("\U0001F4A9", "'{0}'".format("\U0001F4A9")), | |
43 | pytest.param( | |
44 | "\U0001F4A9", | |
45 | "'{0}'".format("\U0001F4A9"), | |
46 | marks=pytest.mark.skipif( | |
47 | platform.python_implementation() == "PyPy", | |
48 | reason="Inexplicable failure on PyPy. Not super important, I hope!", | |
49 | ), | |
50 | ), | |
43 | 51 | ), |
44 | 52 | ) |
45 | 53 | def test_append_description_types(desc, described, appended): |
4 | 4 | |
5 | 5 | import unittest |
6 | 6 | |
7 | from hamcrest.core.base_matcher import * | |
8 | from hamcrest_unit_test.matcher_test import * | |
7 | from hamcrest.core.base_matcher import BaseMatcher | |
8 | from hamcrest_unit_test.matcher_test import assert_match_description, assert_mismatch_description | |
9 | 9 | |
10 | 10 | __author__ = "Jon Reid" |
11 | 11 | __copyright__ = "Copyright 2011 hamcrest.org" |
36 | 36 | def testMatchDescriptionShouldDescribeItem(self): |
37 | 37 | assert_match_description("was <99>", PassingBaseMatcher(), 99) |
38 | 38 | |
39 | def testMatcherReprShouldDescribeMatcher(self): | |
40 | assert repr(FailingBaseMatcher()) == "<FailingBaseMatcher(SOME DESCRIPTION)>" | |
41 | ||
42 | def testMatcherReprShouldTruncateLongDescription(self): | |
43 | class LongDescriptionMatcher(BaseMatcher): | |
44 | def describe_to(self, description): | |
45 | description.append_text("1234 " * 13) | |
46 | ||
47 | assert ( | |
48 | repr(LongDescriptionMatcher()) | |
49 | == "<LongDescriptionMatcher(1234 1234 1234 1234 1234 1234 1234 1234 1234 1234 1234...)>" | |
50 | ) | |
51 | ||
39 | 52 | |
40 | 53 | if __name__ == "__main__": |
41 | 54 | unittest.main() |
0 | from hamcrest.library.collection.is_empty import * | |
0 | from hamcrest.library.collection.is_empty import empty | |
1 | 1 | from hamcrest_unit_test.matcher_test import MatcherTest |
2 | 2 | |
3 | 3 | __author__ = "Chris Rose" |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest import starts_with | |
2 | 3 | from hamcrest.core.core.isequal import equal_to |
3 | from hamcrest.library.collection.isdict_containing import * | |
4 | from hamcrest_unit_test.matcher_test import MatcherTest | |
4 | from hamcrest.library.collection.isdict_containing import has_entry | |
5 | from hamcrest_unit_test.matcher_test import ( | |
6 | MatcherTest, | |
7 | assert_match_description, | |
8 | assert_mismatch_description, | |
9 | ) | |
5 | 10 | |
6 | 11 | from .quasidict import QuasiDictionary |
7 | 12 | |
39 | 44 | def testDescribeMismatch(self): |
40 | 45 | self.assert_describe_mismatch("was 'bad'", has_entry("a", 1), "bad") |
41 | 46 | |
47 | def test_describe_single_matching_key_mismatching_value(self): | |
48 | assert_mismatch_description("value for 'a' was <2>", has_entry("a", 1), {"a": 2}) | |
49 | assert_mismatch_description( | |
50 | "value for 'aa' was <2>", has_entry(starts_with("a"), 1), {"aa": 2} | |
51 | ) | |
52 | assert_mismatch_description( | |
53 | "was <{'ab': 2, 'ac': 3}>", has_entry(starts_with("a"), 1), {"ab": 2, "ac": 3} | |
54 | ) | |
55 | ||
56 | def test_describe_match(self): | |
57 | assert_match_description("value for 'a' was <1>", has_entry("a", 1), {"a": 1, "b": 2}) | |
58 | ||
42 | 59 | |
43 | 60 | if __name__ == "__main__": |
44 | 61 | unittest.main() |
6 | 6 | import unittest |
7 | 7 | |
8 | 8 | from hamcrest.core.core.isequal import equal_to |
9 | from hamcrest.library.collection.isdict_containingentries import * | |
9 | from hamcrest.library.collection.isdict_containingentries import has_entries | |
10 | 10 | from hamcrest_unit_test.matcher_test import MatcherTest |
11 | 11 | |
12 | 12 | __author__ = "Jon Reid" |
0 | 0 | import unittest |
1 | 1 | |
2 | 2 | from hamcrest.core.core.isequal import equal_to |
3 | from hamcrest.library.collection.isdict_containingkey import * | |
3 | from hamcrest.library.collection.isdict_containingkey import has_key | |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 | |
6 | 6 | from .quasidict import QuasiDictionary |
0 | 0 | import unittest |
1 | 1 | |
2 | 2 | from hamcrest.core.core.isequal import equal_to |
3 | from hamcrest.library.collection.isdict_containingvalue import * | |
3 | from hamcrest.library.collection.isdict_containingvalue import has_value | |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 | |
6 | 6 | from .quasidict import QuasiDictionary |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest.library.collection.isin import * | |
2 | from hamcrest.library.collection.isin import is_in | |
3 | 3 | from hamcrest_unit_test.matcher_test import MatcherTest |
4 | 4 | |
5 | 5 | from .sequencemixin import GeneratorForm, SequenceForm |
0 | 0 | import unittest |
1 | 1 | |
2 | 2 | from hamcrest.core.core.isequal import equal_to |
3 | from hamcrest.library.collection.issequence_containing import * | |
3 | from hamcrest.library.collection.issequence_containing import has_item, has_items | |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 | |
6 | 6 | from .quasisequence import QuasiSequence |
0 | 0 | import unittest |
1 | 1 | |
2 | 2 | from hamcrest.core.core.isequal import equal_to |
3 | from hamcrest.library.collection.issequence_containinginanyorder import * | |
3 | from hamcrest.library.collection.issequence_containinginanyorder import contains_inanyorder | |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 | |
6 | 6 | from .quasisequence import QuasiSequence |
0 | 0 | import unittest |
1 | 1 | |
2 | 2 | from hamcrest.core.core.isequal import equal_to |
3 | from hamcrest.library.collection.issequence_containinginorder import * | |
3 | from hamcrest.library.collection.issequence_containinginorder import contains, contains_exactly | |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 | |
6 | 6 | from .quasisequence import QuasiSequence |
0 | 0 | import unittest |
1 | 1 | |
2 | 2 | from hamcrest.core.core.isequal import equal_to |
3 | from hamcrest.library.collection.issequence_onlycontaining import * | |
3 | from hamcrest.library.collection.issequence_onlycontaining import only_contains | |
4 | 4 | from hamcrest.library.number.ordering_comparison import less_than |
5 | 5 | from hamcrest_unit_test.matcher_test import MatcherTest |
6 | 6 |
5 | 5 | |
6 | 6 | import unittest |
7 | 7 | |
8 | from hamcrest.core.core.allof import * | |
8 | from hamcrest.core.core.allof import AllOf, all_of | |
9 | 9 | from hamcrest.core.core.isequal import equal_to |
10 | 10 | from hamcrest_unit_test.matcher_test import MatcherTest |
11 | 11 |
5 | 5 | |
6 | 6 | import unittest |
7 | 7 | |
8 | from hamcrest.core.core.anyof import * | |
8 | from hamcrest.core.core.anyof import any_of | |
9 | 9 | from hamcrest.core.core.isequal import equal_to |
10 | 10 | from hamcrest_unit_test.matcher_test import MatcherTest |
11 | 11 |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest.core.core.described_as import * | |
2 | from hamcrest.core.core.described_as import described_as | |
3 | 3 | from hamcrest.core.core.isanything import anything |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest.core.core.is_ import * | |
2 | from hamcrest.core.core.is_ import is_ | |
3 | 3 | from hamcrest.core.core.isequal import equal_to |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 |
5 | 5 | |
6 | 6 | import unittest |
7 | 7 | |
8 | from hamcrest.core.core.isanything import * | |
8 | from hamcrest.core.core.isanything import anything | |
9 | 9 | from hamcrest_unit_test.matcher_test import MatcherTest |
10 | 10 | |
11 | 11 | __author__ = "Jon Reid" |
5 | 5 | |
6 | 6 | import unittest |
7 | 7 | |
8 | from hamcrest.core.core.isequal import * | |
8 | from hamcrest.core.core.isequal import equal_to | |
9 | 9 | from hamcrest_unit_test.matcher_test import MatcherTest |
10 | 10 | |
11 | 11 | __author__ = "Jon Reid" |
0 | 0 | import sys |
1 | 1 | import unittest |
2 | 2 | |
3 | from hamcrest.core.core.isinstanceof import * | |
3 | from hamcrest.core.core.isinstanceof import instance_of | |
4 | 4 | from hamcrest_unit_test.matcher_test import MatcherTest |
5 | 5 | |
6 | 6 | if __name__ == "__main__": |
5 | 5 | |
6 | 6 | import unittest |
7 | 7 | |
8 | from hamcrest.core.core.isnone import * | |
8 | from hamcrest.core.core.isnone import none, not_none | |
9 | 9 | from hamcrest_unit_test.matcher_test import MatcherTest |
10 | 10 | |
11 | 11 | __author__ = "Jon Reid" |
6 | 6 | import unittest |
7 | 7 | |
8 | 8 | from hamcrest.core.core.isequal import equal_to |
9 | from hamcrest.core.core.isnot import * | |
9 | from hamcrest.core.core.isnot import is_not | |
10 | 10 | from hamcrest_unit_test.matcher_test import MatcherTest |
11 | 11 | |
12 | 12 | __author__ = "Jon Reid" |
6 | 6 | import re |
7 | 7 | import unittest |
8 | 8 | |
9 | from hamcrest.core.core.issame import * | |
9 | from hamcrest.core.core.issame import same_instance | |
10 | 10 | from hamcrest.core.string_description import StringDescription |
11 | 11 | from hamcrest_unit_test.matcher_test import MatcherTest |
12 | 12 |
93 | 93 | |
94 | 94 | self.assert_matches( |
95 | 95 | "Regex", |
96 | raises(AssertionError, "([\d, ]+)"), | |
96 | raises(AssertionError, r"([\d, ]+)"), | |
97 | 97 | calling(raise_exception).with_args(3, 1, 4), |
98 | 98 | ) |
99 | 99 |
6 | 6 | import unittest |
7 | 7 | |
8 | 8 | from hamcrest.core.core.isequal import equal_to |
9 | from hamcrest.library.integration.match_equality import * | |
9 | from hamcrest.library.integration.match_equality import match_equality, tostring | |
10 | 10 | |
11 | 11 | __author__ = "Chris Rose" |
12 | 12 | __copyright__ = "Copyright 2011 hamcrest.org" |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest.library.number.iscloseto import * | |
2 | from hamcrest.library.number.iscloseto import Decimal, close_to, isnumeric | |
3 | 3 | from hamcrest_unit_test.matcher_test import MatcherTest |
4 | 4 | |
5 | 5 | __author__ = "Jon Reid" |
6 | 6 | import unittest |
7 | 7 | from datetime import date |
8 | 8 | |
9 | from hamcrest.library.number.ordering_comparison import * | |
9 | from hamcrest.library.number.ordering_comparison import ( | |
10 | greater_than, | |
11 | greater_than_or_equal_to, | |
12 | less_than, | |
13 | less_than_or_equal_to, | |
14 | ) | |
10 | 15 | from hamcrest_unit_test.matcher_test import MatcherTest |
11 | 16 | |
12 | 17 | __author__ = "Jon Reid" |
7 | 7 | |
8 | 8 | from hamcrest.core.core.isequal import equal_to |
9 | 9 | from hamcrest.library.number.ordering_comparison import greater_than |
10 | from hamcrest.library.object.haslength import * | |
10 | from hamcrest.library.object.haslength import has_length | |
11 | 11 | from hamcrest_unit_test.matcher_test import MatcherTest |
12 | 12 | |
13 | 13 | __author__ = "Jon Reid" |
6 | 6 | import unittest |
7 | 7 | |
8 | 8 | from hamcrest import greater_than |
9 | from hamcrest.library.object.hasproperty import * | |
9 | from hamcrest.library.object.hasproperty import has_properties, has_property | |
10 | 10 | from hamcrest_unit_test.matcher_test import MatcherTest |
11 | 11 | |
12 | 12 | __author__ = "Chris Rose" |
6 | 6 | import unittest |
7 | 7 | |
8 | 8 | from hamcrest.core.core.isequal import equal_to |
9 | from hamcrest.library.object.hasstring import * | |
9 | from hamcrest.library.object.hasstring import has_string | |
10 | 10 | from hamcrest_unit_test.matcher_test import MatcherTest |
11 | 11 | |
12 | 12 | __author__ = "Jon Reid" |
2 | 2 | |
3 | 3 | import pytest |
4 | 4 | from hamcrest.core.selfdescribing import SelfDescribing |
5 | from hamcrest.core.string_description import * | |
5 | from hamcrest.core.string_description import StringDescription | |
6 | 6 | |
7 | 7 | __author__ = "Jon Reid" |
8 | 8 | __copyright__ = "Copyright 2011 hamcrest.org" |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest.library.text.isequal_ignoring_whitespace import * | |
2 | from hamcrest.library.text.isequal_ignoring_whitespace import equal_to_ignoring_whitespace | |
3 | 3 | from hamcrest_unit_test.matcher_test import MatcherTest |
4 | 4 | |
5 | 5 | __author__ = "Jon Reid" |
0 | 0 | import pytest |
1 | 1 | from hamcrest.library.text.stringcontains import contains_string |
2 | from hamcrest_unit_test.matcher_test import * | |
2 | from hamcrest_unit_test.matcher_test import ( | |
3 | assert_description, | |
4 | assert_does_not_match, | |
5 | assert_matches, | |
6 | assert_mismatch_description, | |
7 | assert_no_mismatch_description, | |
8 | ) | |
3 | 9 | |
4 | 10 | __author__ = "Jon Reid" |
5 | 11 | __copyright__ = "Copyright 2011 hamcrest.org" |
58 | 64 | |
59 | 65 | |
60 | 66 | if __name__ == "__main__": |
67 | import unittest | |
68 | ||
61 | 69 | unittest.main() |
0 | if __name__ == "__main__": | |
1 | import sys | |
2 | ||
3 | sys.path.insert(0, "..") | |
4 | sys.path.insert(0, "../..") | |
5 | ||
6 | import unittest | |
7 | ||
8 | from hamcrest.core.string_description import StringDescription | |
9 | from hamcrest.library.text import string_contains_in_order | |
10 | from hamcrest_unit_test.matcher_test import MatcherTest | |
11 | ||
12 | __author__ = "Romilly Cocking" | |
13 | __copyright__ = "Copyright 2011 hamcrest.org" | |
14 | __license__ = "BSD, see License.txt" | |
15 | ||
16 | ||
17 | matcher = string_contains_in_order("string one", "string two", "string three") | |
18 | ||
19 | ||
20 | class StringContainsInOrderTest(MatcherTest): | |
21 | def testMatchesIfOrderIsCorrect(self): | |
22 | self.assert_matches( | |
23 | "correct order", matcher, "string one then string two followed by string three" | |
24 | ) | |
25 | ||
26 | def testDoesNotMatchIfOrderIsIncorrect(self): | |
27 | self.assert_does_not_match( | |
28 | "incorrect order", matcher, "string two then string one followed by string three" | |
29 | ) | |
30 | ||
31 | def testDoesNotMatchIfExpectedSubstringsAreMissing(self): | |
32 | self.assert_does_not_match("missing string one", matcher, "string two then string three") | |
33 | self.assert_does_not_match("missing string two", matcher, "string one then string three") | |
34 | self.assert_does_not_match("missing string three", matcher, "string one then string two") | |
35 | ||
36 | def testMatcherCreationRequiresString(self): | |
37 | self.assertRaises(TypeError, string_contains_in_order, 3) | |
38 | ||
39 | def testFailsIfMatchingAgainstNonString(self): | |
40 | self.assert_does_not_match("non-string", matcher, object()) | |
41 | ||
42 | def testHasAReadableDescription(self): | |
43 | self.assert_description( | |
44 | "a string containing 'string one', 'string two', 'string three' in order", matcher | |
45 | ) | |
46 | ||
47 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
48 | self.assert_no_mismatch_description( | |
49 | matcher, "string one then string two followed by string three" | |
50 | ) | |
51 | ||
52 | def testMismatchDescription(self): | |
53 | self.assert_mismatch_description("was 'bad'", matcher, "bad") | |
54 | ||
55 | def testDescribeMismatch(self): | |
56 | self.assert_describe_mismatch("was 'bad'", matcher, "bad") | |
0 | from hamcrest.library.text import string_contains_in_order | |
1 | from hamcrest_unit_test.matcher_test import MatcherTest | |
2 | ||
3 | __author__ = "Romilly Cocking" | |
4 | __copyright__ = "Copyright 2011 hamcrest.org" | |
5 | __license__ = "BSD, see License.txt" | |
6 | ||
7 | ||
8 | matcher = string_contains_in_order("string one", "string two", "string three") | |
9 | ||
10 | ||
11 | class StringContainsInOrderTest(MatcherTest): | |
12 | def testMatchesIfOrderIsCorrect(self): | |
13 | self.assert_matches( | |
14 | "correct order", matcher, "string one then string two followed by string three" | |
15 | ) | |
16 | ||
17 | def testDoesNotMatchIfOrderIsIncorrect(self): | |
18 | self.assert_does_not_match( | |
19 | "incorrect order", matcher, "string two then string one followed by string three" | |
20 | ) | |
21 | ||
22 | def testDoesNotMatchIfExpectedSubstringsAreMissing(self): | |
23 | self.assert_does_not_match("missing string one", matcher, "string two then string three") | |
24 | self.assert_does_not_match("missing string two", matcher, "string one then string three") | |
25 | self.assert_does_not_match("missing string three", matcher, "string one then string two") | |
26 | ||
27 | def testMatcherCreationRequiresString(self): | |
28 | self.assertRaises(TypeError, string_contains_in_order, 3) | |
29 | ||
30 | def testFailsIfMatchingAgainstNonString(self): | |
31 | self.assert_does_not_match("non-string", matcher, object()) | |
32 | ||
33 | def testHasAReadableDescription(self): | |
34 | self.assert_description( | |
35 | "a string containing 'string one', 'string two', 'string three' in order", matcher | |
36 | ) | |
37 | ||
38 | def testSuccessfulMatchDoesNotGenerateMismatchDescription(self): | |
39 | self.assert_no_mismatch_description( | |
40 | matcher, "string one then string two followed by string three" | |
41 | ) | |
42 | ||
43 | def testMismatchDescription(self): | |
44 | self.assert_mismatch_description("was 'bad'", matcher, "bad") | |
45 | ||
46 | def testDescribeMismatch(self): | |
47 | self.assert_describe_mismatch("was 'bad'", matcher, "bad") |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest.library.text.stringendswith import * | |
2 | from hamcrest.library.text.stringendswith import ends_with | |
3 | 3 | from hamcrest_unit_test.matcher_test import MatcherTest |
4 | 4 | |
5 | 5 | __author__ = "Jon Reid" |
3 | 3 | sys.path.insert(0, "..") |
4 | 4 | sys.path.insert(0, "../..") |
5 | 5 | |
6 | import re | |
6 | 7 | import unittest |
7 | 8 | |
8 | from hamcrest.library.text.stringmatches import * | |
9 | from hamcrest.library.text.stringmatches import matches_regexp | |
9 | 10 | from hamcrest_unit_test.matcher_test import MatcherTest |
10 | 11 | |
11 | 12 | __author__ = "Chris Rose" |
0 | 0 | import unittest |
1 | 1 | |
2 | from hamcrest.library.text.stringstartswith import * | |
2 | from hamcrest.library.text.stringstartswith import starts_with | |
3 | 3 | from hamcrest_unit_test.matcher_test import MatcherTest |
4 | 4 | |
5 | 5 | __author__ = "Jon Reid" |
2 | 2 | class MyTest(object): |
3 | 3 | pass |
4 | 4 | |
5 | ||
6 | 5 | except TypeError: |
7 | 6 | print("Object class defined at {0}".format(getattr(object, "__file__", "NOWHERE"))) |
8 | 7 | raise |
0 | - case: is | |
1 | # pypy + mypy doesn't work. See https://foss.heptapod.net/pypy/pypy/-/issues/3526 | |
2 | skip: platform.python_implementation() == "PyPy" | |
3 | main: | | |
4 | from hamcrest import assert_that, is_, empty | |
5 | from typing import Any, Sequence | |
6 | ||
7 | a: Sequence[Any] = [] | |
8 | b = 99 | |
9 | ||
10 | assert_that(a, is_(empty())) | |
11 | assert_that(b, is_(empty())) # E: Cannot infer type argument 1 of "assert_that" |
0 | - case: assert_that | |
1 | # pypy + mypy doesn't work. See https://foss.heptapod.net/pypy/pypy/-/issues/3526 | |
2 | skip: platform.python_implementation() == "PyPy" | |
3 | main: | | |
4 | from hamcrest import assert_that, instance_of, starts_with | |
5 | ||
6 | assert_that("string", starts_with("str")) | |
7 | assert_that("str", instance_of(str)) | |
8 | assert_that(99, starts_with("str")) | |
9 | out: | | |
10 | main:5: error: Cannot infer type argument 1 of "assert_that" |
0 | - case: empty | |
1 | # pypy + mypy doesn't work. See https://foss.heptapod.net/pypy/pypy/-/issues/3526 | |
2 | skip: platform.python_implementation() == "PyPy" | |
3 | main: | | |
4 | from hamcrest import assert_that, is_, empty | |
5 | ||
6 | assert_that([], empty()) | |
7 | assert_that(99, empty()) # E: Cannot infer type argument 1 of "assert_that"⏎ |
0 | - case: equal_to_ignoring_case | |
1 | # pypy + mypy doesn't work. See https://foss.heptapod.net/pypy/pypy/-/issues/3526 | |
2 | skip: platform.python_implementation() == "PyPy" | |
3 | main: | | |
4 | from hamcrest import equal_to_ignoring_case | |
5 | ||
6 | reveal_type(equal_to_ignoring_case("")) | |
7 | equal_to_ignoring_case("") | |
8 | equal_to_ignoring_case(99) | |
9 | out: | | |
10 | main:3: note: Revealed type is "hamcrest.core.matcher.Matcher[builtins.str]" | |
11 | main:5: error: Argument 1 to "equal_to_ignoring_case" has incompatible type "int"; expected "str" |
0 | - case: equal_to_ignoring_case | |
1 | main: | | |
2 | from hamcrest.library.text.isequal_ignoring_case import equal_to_ignoring_case | |
3 | ||
4 | reveal_type(equal_to_ignoring_case("")) # N: Revealed type is 'builtins.str*' |
0 | [pytest] | |
1 | addopts = -ra | |
2 | testpaths = tests | |
3 | xfail_strict = true | |
4 | filterwarnings = | |
5 | once::Warning | |
6 | ignore:::pympler[.*] | |
7 | looponfailroots = | |
8 | src | |
9 | tests | |
10 | ||
11 | # Keep docs in sync with docs env and .readthedocs.yml. | |
12 | [gh-actions] | |
13 | python = | |
14 | 3.6: py36, py36-numpy | |
15 | 3.7: py37, py37-numpy | |
16 | 3.8: py38, py38-numpy | |
17 | 3.9: py39, py39-numpy, lint, manifest, typing, changelog, docs | |
18 | 3.10: py310 | |
19 | pypy-2: pypy2 | |
20 | pypy-3: pypy3 | |
21 | ||
22 | ||
0 | 23 | [tox] |
1 | envlist = py35,py36,py37,py38,pypy2.7,pypy3.6,docs-py3 | |
2 | # Jython is not testable, but there's no reason it should not work. | |
24 | envlist = typing,lint,py36{,-numpy},py37{,-numpy},py38{,-numpy},py39{,-numpy},py310{,-numpy},pypy{,-numpy},pypy3{,-numpy},manifest,docs,pypi-description,changelog,coverage-report | |
25 | isolated_build = True | |
26 | ||
3 | 27 | |
4 | 28 | [testenv] |
5 | commands = {envbindir}/py.test [] | |
6 | {envpython} tests/object_import.py | |
7 | deps = pytest~=5.0 | |
8 | pytest-cov~=2.0 | |
29 | # Prevent random setuptools/pip breakages like | |
30 | # https://github.com/pypa/setuptools/issues/1042 from breaking our builds. | |
31 | setenv = | |
32 | VIRTUALENV_NO_DOWNLOAD=1 | |
33 | extras = {env:TOX_AP_TEST_EXTRAS:tests} | |
34 | commands = python -m pytest {posargs} | |
9 | 35 | |
10 | [testenv:jython] | |
11 | deps = pytest | |
12 | commands = {envbindir}/jython tests/alltests.py [] | |
13 | {envpython} tests/object_import.py | |
36 | ||
37 | [testenv:py27] | |
38 | extras = {env:TOX_AP_TEST_EXTRAS:tests} | |
39 | commands = coverage run -m pytest {posargs} | |
14 | 40 | |
15 | 41 | [testenv:py36-numpy] |
16 | basepython = python3.6 | |
17 | deps = {[testenv]deps} | |
18 | numpy | |
19 | setenv = | |
20 | PYTHONHASHSEED = 4 | |
42 | extras = tests-numpy | |
43 | commands = python -m pytest {posargs} | |
21 | 44 | |
22 | [testenv:docs-py3] | |
23 | basepython = python3.6 | |
24 | deps = sphinx | |
25 | sphinx_rtd_theme | |
26 | changedir = {toxinidir}/doc | |
27 | commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html | |
45 | [testenv:py37-numpy] | |
46 | extras = tests-numpy | |
47 | commands = python -m pytest {posargs} | |
28 | 48 | |
29 | [testenv:format] | |
30 | basepython = python3 | |
49 | [testenv:py38-numpy] | |
50 | extras = tests-numpy | |
51 | commands = python -m pytest {posargs} | |
52 | ||
53 | [testenv:py39-numpy] | |
54 | extras = tests-numpy | |
55 | commands = python -m pytest {posargs} | |
56 | ||
57 | [testenv:py37] | |
58 | # Python 3.6+ has a number of compile-time warnings on invalid string escapes. | |
59 | # PYTHONWARNINGS=d and --no-compile below make them visible during the Tox run. | |
60 | install_command = pip install --no-compile {opts} {packages} | |
61 | setenv = | |
62 | PYTHONWARNINGS=d | |
63 | extras = {env:TOX_AP_TEST_EXTRAS:tests} | |
64 | commands = coverage run -m pytest {posargs} | |
65 | ||
66 | ||
67 | [testenv:py38] | |
68 | # Python 3.6+ has a number of compile-time warnings on invalid string escapes. | |
69 | # PYTHONWARNINGS=d and --no-compile below make them visible during the Tox run. | |
70 | basepython = python3.8 | |
71 | install_command = pip install --no-compile {opts} {packages} | |
72 | setenv = | |
73 | PYTHONWARNINGS=d | |
74 | extras = {env:TOX_AP_TEST_EXTRAS:tests} | |
75 | commands = coverage run -m pytest {posargs} | |
76 | ||
77 | ||
78 | [testenv:py39] | |
79 | # Python 3.6+ has a number of compile-time warnings on invalid string escapes. | |
80 | # PYTHONWARNINGS=d and --no-compile below make them visible during the Tox run. | |
81 | basepython = python3.9 | |
82 | install_command = pip install --no-compile {opts} {packages} | |
83 | setenv = | |
84 | PYTHONWARNINGS=d | |
85 | extras = {env:TOX_AP_TEST_EXTRAS:tests} | |
86 | commands = coverage run -m pytest {posargs} | |
87 | ||
88 | [testenv:py310] | |
89 | # Python 3.6+ has a number of compile-time warnings on invalid string escapes. | |
90 | # PYTHONWARNINGS=d and --no-compile below make them visible during the Tox run. | |
91 | basepython = python3.10 | |
92 | install_command = pip install --no-compile {opts} {packages} | |
93 | setenv = | |
94 | PYTHONWARNINGS=d | |
95 | extras = {env:TOX_AP_TEST_EXTRAS:tests} | |
96 | commands = coverage run -m pytest {posargs} | |
97 | ||
98 | [testenv:coverage-report] | |
99 | basepython = python3.9 | |
100 | skip_install = true | |
101 | deps = coverage[toml]>=5.0.2 | |
102 | commands = | |
103 | coverage combine | |
104 | coverage report | |
105 | ||
106 | ||
107 | [testenv:lint] | |
108 | basepython = python3.9 | |
31 | 109 | skip_install = true |
32 | 110 | deps = |
33 | black~=19.10b0 | |
34 | isort~=4.0 | |
111 | pre-commit | |
112 | passenv = HOMEPATH # needed on Windows | |
35 | 113 | commands = |
36 | isort {toxinidir}/setup.py | |
37 | isort -rc {toxinidir}/src/ | |
38 | isort -rc {toxinidir}/tests/ | |
39 | black -l100 -tpy35 src/ tests/ setup.py | |
114 | pre-commit run --all-files | |
40 | 115 | |
41 | [testenv:check-format] | |
42 | basepython = python3 | |
116 | ||
117 | [testenv:docs] | |
118 | # Keep basepython in sync with gh-actions and .readthedocs.yml. | |
119 | basepython = python3.9 | |
120 | extras = docs | |
121 | commands = | |
122 | sphinx-build -n -T -b html -d {envtmpdir}/doctrees doc doc/_build/html | |
123 | ||
124 | ||
125 | [testenv:manifest] | |
126 | basepython = python3.9 | |
127 | deps = check-manifest | |
43 | 128 | skip_install = true |
44 | deps = {[testenv:format]deps} | |
45 | commands = | |
46 | isort --check-only {toxinidir}/setup.py | |
47 | isort --check-only -rc {toxinidir}/src/ | |
48 | isort --check-only -rc {toxinidir}/tests/ | |
49 | black --check -l100 -tpy35 src/ tests/ setup.py | |
129 | commands = check-manifest | |
50 | 130 | |
51 | [tool:isort] | |
52 | multi_line_output=3 | |
53 | include_trailing_comma=True | |
54 | force_grid_wrap=0 | |
55 | use_parentheses=True | |
56 | line_length=100 | |
57 | 131 | |
58 | [testenv:flake8] | |
59 | basepython = python3 | |
132 | [testenv:pypi-description] | |
133 | basepython = python3.9 | |
60 | 134 | skip_install = true |
61 | 135 | deps = |
62 | flake8~=3.0 | |
63 | flake8-bugbear~=18.0 | |
64 | flake8-comprehensions~=1.0 | |
65 | flake8-mutable~=1.0 | |
66 | mccabe~=0.6 | |
67 | flake8-blind-except~=0.1 | |
68 | flake8-builtins~=1.0 | |
69 | flake8-pep3101~=1.0 | |
70 | flake8-print~=3.0 | |
71 | flake8-string-format~=0.2 | |
72 | flake8-logging-format~=0.5 | |
136 | twine | |
137 | pip >= 18.0.0 | |
138 | commands = | |
139 | pip wheel -w {envtmpdir}/build --no-deps . | |
140 | twine check {envtmpdir}/build/* | |
73 | 141 | |
142 | ||
143 | [testenv:changelog] | |
144 | basepython = python3.9 | |
145 | deps = towncrier | |
146 | skip_install = true | |
147 | commands = towncrier --draft | |
148 | ||
149 | ||
150 | [testenv:typing] | |
151 | basepython = python3.9 | |
152 | deps = | |
153 | mypy | |
154 | types-mock | |
74 | 155 | commands = |
75 | flake8 src/ tests/ setup.py | |
156 | mypy src/ | |
157 | ||
158 | ||
76 | 159 | |
77 | 160 | [flake8] |
78 | max-complexity = 5 | |
161 | max-complexity = 15 | |
79 | 162 | max-line-length = 100 |
80 | 163 | show-source = True |
81 | 164 | enable-extensions = M,B,C,T,P |
82 | 165 | ignore = C812,W503,P103,E1,E2,E3,E5 |
83 | 166 | statistics = True |
84 | ||
85 | [testenv:mypy] | |
86 | basepython = python3.8 | |
87 | skip_install = true | |
88 | deps = | |
89 | mypy~=0.6 | |
90 | commands = | |
91 | mypy src/ tests/ --ignore-missing-imports {posargs} | |
92 | ||
93 | [testenv:test-hinting] | |
94 | basepython = python3 | |
95 | skip_install = true | |
96 | deps = | |
97 | pytest-mypy-plugins~=1.0 | |
98 | commands = | |
99 | pytest --mypy-ini-file=tox.ini tests/type-hinting/ {posargs} | |
100 | ||
101 | [testenv:pyre] | |
102 | basepython = python3.7 | |
103 | skip_install = true | |
104 | deps = | |
105 | pyre-check | |
106 | commands = | |
107 | pyre --source-directory src/ check {posargs} | |
108 | pyre --source-directory tests/ --search-path src/ check {posargs} | |
167 | per-file-ignores = | |
168 | src/*/__init__.py:F401,F403,F405 | |
169 | src/hamcrest/__init__.py:F401,F403 |