@@ -12,7 +12,7 @@ Overview
1212
1313This package provides a Python script and pytest plugin to help convert Nose-based tests into pytest-based
1414tests. Specifically, the script transforms ``nose.tools.assert_* `` function calls into raw assert statements,
15- while preserving format of original arguments as much as possible. For example, the script:
15+ while preserving the format of original arguments as much as possible. For example, the script:
1616
1717.. code-block :: python
1818
@@ -31,35 +31,36 @@ transformed because there is no raw assert statement equivalent, or the equivale
3131maintain. They are provided as functions in the pytest namespace via pytest's plugin system.
3232
3333
34- Installation
35- -------------
36-
37- From a command shell run ::
38-
39- pip install nose2pytest
40-
41- This puts an executable file in ``<python-root>/Scripts `` with *python-root * being the root folder of the
42- Python installation from which ``pip `` was run.
43-
44-
4534Running
4635------------
4736
48- From a command shell, ::
37+ For a one-time conversion use the shell command ::
4938
50- nose2pytest path/to/dir/with/python_files
39+ pipx run --python 3.11 nose2pytest path/to/dir/with/python_files
5140
5241This will find all ``.py `` files in the folder tree starting at ``path/to/dir/with/python_files `` and
5342overwrite the original (assuming most users will be running this on a version-controlled code base, this is
5443almost always what would be most convenient). Type ``nose2pytest -h `` for other options, such as ``-v ``.
5544
5645
46+ Installation
47+ -------------
48+
49+ For doing multiple conversions use the shell command ::
50+
51+ pipx install --python 3.11 nose2pytest
52+
53+ For each conversion use the shell command ::
54+
55+ nose2pytest path/to/dir/with/python_files
56+
57+
5758Motivation
5859------------
5960
6061I have used Nose for years and it is a great tool. However, to get good test failure diagnostics with Nose you
6162ought to use the ``assert_*() `` functions from ``nose.tools ``. Although they provide very good diagnostics, they
62- are not as convenient to use as raw assertions, since you have to decide before hand what type of assertion you
63+ are not as convenient to use as raw assertions, since you have to decide beforehand what type of assertion you
6364are going to write: an identity comparison to None, a truth check, a falseness check, an identity comparison to another
6465object, etc. Just being able to write a raw assertion, and still get good diagnostics on failure as done by
6566pytest, is really nice. This is a main reason for using pytest for me. Another reason is the design of fixtures
@@ -72,7 +73,7 @@ manually, to get the same test coverage and results. A few gotchas:
7273- test classes that have ``__init__ `` will be ignored, those will have to be moved (usually, into class's
7374 ``setup_class() ``)
7475- the ``setup.cfg `` may have to be edited since test discovery rules are slightly more strict with pytest
75- - the order of tests may be different, but in general that should not matter
76+ - the order of tests may be different, but in general, that should not matter
7677- all test modules are imported up-front, so some test modules may need adjustment such as moving some
7778 code from the top of the test module into its ``setup_module() ``
7879
@@ -83,7 +84,7 @@ uses ``nose.tools.assert_*`` functions, yet with pytest you can use raw assertio
8384these two approaches should a developer use? If you modify existing tests, should new assertions use raw assert?
8485Should the remaining test method, test class, or test module be updated? A test module can contain hundreds of
8586calls to ``nose.tools.assert_* `` functions, is a developer to manually go through each one to convert it? Painful and
86- error prone, in general not feasible to do manually.
87+ error- prone, in general not feasible to do manually.
8788
8889This is why I developed nose2pytest: I wanted to migrate my pypubsub project's test suite from Nose to pytest,
8990but also have only pytest as a dependency, and have one obvious way to write assertions in the test suite.
@@ -92,14 +93,9 @@ but also have only pytest as a dependency, and have one obvious way to write ass
9293Requirements
9394-------------
9495
95- I expect nose2pytest script to run with Python >= 3.4, to correctly convert Python test suite >= 2.7, on any
96- OS supported by a version of python that has lib2to3 compatible with Python 3.4's lib2to3. I expect it to
97- succeed even with quite old versions of Nose (even prior to 1.0 which came out ca. 2010), and with the new
98- Nose2 test driver.
99-
100- Note however that I have run the script only with Python 3.4, to convert Python 3.4 test suites based on
101- Nose 1.3.7 on Windows 7 Pro 64. If you have successfully used nose2pytest with other combinations, please
102- kindly let me know (via github).
96+ I expect nose2pytest script to run with supported versions of CPython <= v3.11, on any OS supported by a version of
97+ Python that has lib2to3 compatible with fissix. I expect it to succeed even with quite old versions of Nose (even
98+ prior to 1.0 which came out ca. 2010) and with the new Nose2 test driver.
10399
104100The pytest package namespace will be extended with ``assert_ `` functions that are not converted by the script
105101only if, err, you have pytest installed!
@@ -207,7 +203,7 @@ Limitations
207203
208204- The script does not convert ``nose.tools.assert_ `` import statements as there are too many possibilities.
209205 Should ``from nose.tools import ... `` be changed to ``from pytest import ... ``, and the implemented
210- conversions removed? Should an ``import pytest `` statement be added, and if so, where? If it is added after
206+ conversions be removed? Should an ``import pytest `` statement be added, and if so, where? If it is added after
211207 the line that had the ``nose.tools `` import, is the previous line really needed? Indeed the ``assert_ ``
212208 functions added in the ``pytest `` namespace could be accessed via ``pytest.assert_ ``, in which case the
213209 script should prepend ``pytest. `` and remove the ``from nose.tools import ... `` entirely. Too many options,
@@ -229,30 +225,17 @@ Limitations
229225 import bogo.assert_true
230226 bogo.assert_true(... ) # should this one be converted?
231227
232- The possiblities are endless so supporting this would require such a large amount of time that I
228+ The possibilities are endless so supporting this would require such a large amount of time that I
233229 do not have. As with other limitations in this section
234230
235231- Nose functions that can be used as context managers can obviously not be converted to raw assertions.
236232 However, there is currently no way of preventing nose2pytest from converting Nose functions used this way.
237233 You will have to manually fix.
238-
239- - The lib2to3 package that nose2pytest relies on assumes python 2.7 syntax as input. The only issue that
240- this has caused so far on code base of 20k lines of python 3.4 *test * code (i.e. the source code does not
241- matter, as none of the test code, such as import statements, is actually run) are keywords like ``exec ``
242- and ``print ``, which in Python 2.x were statements, whereas they are functions in Python 3.x. This means
243- that in Python 3.x, a method can be named ``exec() `` or ``print() ``, whereas this would lead to a syntax
244- error in Python 2.7. Some libraries that do not support 2.x take advantage of this (like PyQt5). Any
245- occurrence of these two keywords as methods in your test code will cause the script to fail converting
246- anything.
247-
248- The work around is, luckily, simple: do a global search-replace of ``\.exec\( `` for ``.exec__( `` in your
249- test folder, run nose2pytest, then reverse the search-replace (do a global search-replace of ``\.exec__\( ``
250- for ``.exec( ``).
251-
234+
252235- ``@raises ``: this decorator can be replaced via the regular expression ``@raises\((.*)\) `` to
253236 ``@pytest.mark.xfail(raises=$1) ``,
254237 but I prefer instead to convert such decorated test functions to use ``pytest.raises `` in the test function body.
255- Indeed, it is easy to forget the decorator, and add code after the line that raises, but this code will never
238+ Indeed, it is easy to forget the decorator and add code after the line that raises, but this code will never
256239 be run and you won't know. Using the ``pytest.raises(...) `` is better than ``xfail(raise=...) ``.
257240
258241- Nose2pytest does not have a means of determining if an assertion function is inside a lambda expression, so
@@ -281,16 +264,17 @@ should be able to run both a unittest2pytest converter, then the nose2pytest con
281264Solution Notes
282265---------------
283266
284- I don't think this script would have been possible without lib2to3, certainly not with the same functionality since
285- lib2to3, due to its purpose, preserves newlines, spaces and comments. The documentation for lib2to3 is very
286- minimal, so I was lucky to find http://python3porting.com/fixers.html.
267+ I don't think this script would have been possible without lib2to3/fissix, certainly not with the same
268+ functionality since lib2to3/fissix, due to their purpose, preserves newlines, spaces and comments. The
269+ documentation for lib2to3/fissix is very minimal, so I was lucky to
270+ find http://python3porting.com/fixers.html.
287271
288- Other than figuring out lib2to3 package so I could harness its
289- capabilities, some aspects of code transformations still turned out to be tricky, as warned by Regobro in the
290- last paragraph of his `Extending 2to3 <http://python3porting.com/fixers.html >`_ page.
272+ Other than figuring out lib2to3/fissix package so I could harness its capabilities, some aspects of code
273+ transformations still turned out to be tricky, as warned by Regobro in the last paragraph of his
274+ `Extending 2to3 <http://python3porting.com/fixers.html >`_ page.
291275
292276- Multi-line arguments: Python accepts multi-line expressions when they are surrounded by parentheses, brackets
293- or braces, but not otherwise. For example converting:
277+ or braces, but not otherwise. For example, converting:
294278
295279 .. code-block :: python
296280
@@ -313,7 +297,7 @@ last paragraph of his `Extending 2to3 <http://python3porting.com/fixers.html>`_
313297
314298 So nose2pytest checks each argument expression (such as ``long_a +\n long_b ``) to see if it has
315299 newlines that would cause an invalid syntax, and if so, wraps them in parentheses. However, it is also important
316- for readability of raw assertions that parentheses only be present if necessary. In other words:
300+ for the readability of raw assertions that parentheses only be present if necessary. In other words:
317301
318302 .. code-block :: python
319303
@@ -342,10 +326,10 @@ last paragraph of his `Extending 2to3 <http://python3porting.com/fixers.html>`_
342326
343327 So nose2pytest only tries to limit the addition of external parentheses to code that really needs it.
344328
345- - Operator precedence: Python assigns a precedence to each operator; operators that are on the same level
329+ - Operator precedence: Python assigns precedence to each operator; operators that are on the same level
346330 of precedence (like the comparison operators ==, >=, !=, etc) are executed in sequence. This poses a problem
347331 for two-argument assertion functions. Example: translating ``assert_equal(a != b, a <= c) `` to
348- ``assert a != b == a <= c `` is incorrect, it must be converted to ``assert (a != b) == (a <= c) ``. However
332+ ``assert a != b == a <= c `` is incorrect, it must be converted to ``assert (a != b) == (a <= c) ``. However,
349333 wrapping every argument in parentheses all the time does not produce easy-to-read assertions:
350334 ``assert_equal(a, b < c) `` should convert to ``assert a == (b < c) ``, not ``assert (a) == (b < c) ``.
351335
@@ -358,20 +342,20 @@ last paragraph of his `Extending 2to3 <http://python3porting.com/fixers.html>`_
358342Contributing
359343------------
360344
361- Patches and extensions are welcome. Please fork, branch, then submit PR. Nose2pytest uses `lib2to3.pytree `,
345+ Patches and extensions are welcome. Please fork, branch, and then submit PR. Nose2pytest uses `lib2to3.pytree `,
362346in particular the Leaf and Node classes. There are a few particularly challenging aspects to transforming
363347nose test expressions to equivalent pytest expressions:
364348
365349#. Finding expressions that match a pattern: If the code you want to transform does not already match one
366- of the uses cases in script.py, you will have to determine the lib2to3 pattern expression
350+ of the uses cases in script.py, you will have to determine the lib2to3/fissix pattern expression
367351 that describes it (this is similar to regular expressions, but for AST representation of code,
368352 instead of text strings). Various expression patterns already exist near the top of
369353 nose2pytest/script.py. This is largely trial and error as there is (as of this writing) no good
370354 documentation.
371- #. Inserting the sub-expressions extracted by lib2to3 in step 1 into the target "expression template". For
372- example to convert `assert_none(a) ` to `assert a is None `, the `a ` sub-expression extracted via the lib2to3
373- pattern must be inserted into the correct "placeholder" node of the target expression. If step 1 was
374- necessary, then step 2 like involves creating a new class that derives from `FixAssertBase `.
355+ #. Inserting the sub-expressions extracted by lib2to3/fissix in step 1 into the target "expression template".
356+ For example to convert `assert_none(a) ` to `assert a is None `, the `a ` sub-expression extracted via the
357+ lib2to3/fissix pattern must be inserted into the correct "placeholder" node of the target expression. If
358+ step 1 was necessary, then step 2 like involves creating a new class that derives from `FixAssertBase `.
375359#. Parentheses and priority of operators: sometimes, it is necessary to add parentheses around an extracted
376360 subexpression to protect it against higher-priority operators. For example, in `assert_none(a) ` the `a `
377361 could be an arbitrary Python expression, such as `var1 and var2 `. The meaning of `assert_none(var1 and var2) `
@@ -431,10 +415,10 @@ Maintenance
431415
432416- Clone or fork the git repo, create a branch
433417- Install `pytest ` and `nose ` on your system: `python -m pip install pytest nose `
434- - In root folder, run `pytest `
418+ - In the root folder, run `pytest `
435419- Once all tests pass, install tox on your system: on Ubuntu, `python -m pip install tox `
436420- Run tox: `tox `
437- - Add a python version if latest python is not in `tox.ini `
421+ - Add a python version if the latest Python is not in `tox.ini `
438422
439423Notes for Ubuntu:
440424- My experience today installing python 3.5 to 3.11 on Ubuntu 18 was surprisingly not smooth. I had to use these
@@ -448,8 +432,8 @@ Notes for Ubuntu:
448432 - note however that once the correct tox installed,
449433
450434
451- Acknowledgements
452- ----------------
435+ Acknowledgments
436+ ---------------
453437
454438Thanks to (AFAICT) Lennart Regebro for having written http://python3porting.com/fixers.html#find-pattern, and
455439to those who answered
0 commit comments