Significant changes: now targets only Python 3.1, and recording the new status (and rationale) as rejected by BDFL pronouncement.
Feel free to mine for ideas. :PEP: XXX :Title: Consolidating names in the `unittest` module :Version: 0.4 :Last-Modified: 2008-07-17 :Author: Ben Finney <[EMAIL PROTECTED]> :Status: Rejected :Type: Standards Track :Content-Type: test/x-rst :Created: 2008-07-14 :Python-Version: 3.1 :Post-History: .. contents:: Abstract ======== This PEP proposes to consolidate the names that constitute the API of the standard library `unittest` module, with the goal of removing redundant names, and conforming with PEP 8. Motivation ========== The normal use case for the `unittest` module is to subclass its classes, overriding and re-using its functions and methods. This draws constant attention to the fact that the existing implementation fails several current Python standards: * It does not conform to `PEP 8`_, requiring users to write their own non-PEP-8-conformant names when overriding methods, and encouraging extensions to further depart from PEP 8. * It has many synonyms in its API, which goes against `PEP 20`_. Specification ============= Remove obsolete names --------------------- The following module attributes are not documented as part of the API and are marked as obsolete in the implementation. They will be removed. * ``_makeLoader`` * ``getTestCaseNames`` * ``makeSuite`` * ``findTestCases`` Remove redundant names ---------------------- The following attribute names exist only as synonyms for other names. They are to be removed, leaving only one name for each attribute in the API. ``TestCase`` attributes ~~~~~~~~~~~~~~~~~~~~~~~ ``assert_`` Use ``assert_true``, or an ``assert`` statement. ``assertEquals`` Use ``assert_equal``. ``assertNotEquals`` Use ``assert_not_equal``. ``assertAlmostEquals`` Use ``assert_almost_equal``. ``assertNotAlmostEquals`` Use ``assert_not_almost_equal``. ``failIf`` Use ``assert_false``. ``failUnless`` Use ``assert_true``. ``failIfAlmostEqual`` Use ``assert_not_almost_equal``. ``failIfEqual`` Use ``assert_not_equal``. ``failUnlessAlmostEqual`` Use ``assert_almost_equal``. ``failUnlessEqual`` Use ``assert_equal``. ``failUnlessRaises`` Use ``assert_raises``. Conform API with PEP 8 ---------------------- The following names are to be introduced, each replacing an existing name, to make all names in the module conform with `PEP 8`_. Each name is shown with the existing name that it replaces. Where function parameters are to be renamed also, they are shown. Where function parameters are not to be renamed, they are elided with the ellipse ("…") symbol. Module attributes ~~~~~~~~~~~~~~~~~ ``default_test_loader`` Replaces ``defaultTestLoader`` ``TestResult`` attributes ~~~~~~~~~~~~~~~~~~~~~~~~~ ``add_error(…)`` Replaces ``addError(…)`` ``add_result(…)`` Replaces ``addResult(…)`` ``add_success(…)`` Replaces ``addSuccess(…)`` ``should_stop`` Replaces ``shouldStop`` ``start_test(…)`` Replaces ``startTest(…)`` ``stop_test(…)`` Replaces ``stopTest(…)`` ``tests_run`` Replaces ``testsRun`` ``was_successful(…)`` Replaces ``wasSuccessful(…)`` ``TestCase`` attributes ~~~~~~~~~~~~~~~~~~~~~~~ ``__init__(self, method_name='run_test')`` Replaces ``__init__(self, methodName='runTest')`` ``_test_method_doc`` Replaces ``_testMethodDoc`` ``_test_method_name`` Replaces ``_testMethodName`` ``failure_exception`` Replaces ``failureException`` ``count_test_cases(…)`` Replaces ``countTestCases(…)`` ``default_test_result(…)`` Replaces ``defaultTestResult(…)`` ``assert_true(…)`` Replaces ``assertTrue(…)`` ``assert_false(…)`` Replaces ``assertFalse(…)`` ``assert_almost_equal(…)`` Replaces ``assertAlmostEqual(…)`` ``assert_equal(…)`` Replaces ``assertEqual(…)`` ``assert_not_almost_equal(…)`` Replaces ``assertNotAlmostEqual(…)`` ``assert_not_equal(…)`` Replaces ``assertNotEqual(…)`` ``assert_raises(exc_class, callable_obj, *args, **kwargs)`` Replaces ``assertRaises(excClass, callableObj, *args, **kwargs)`` ``run_test(…)`` Replaces ``runTest(…)`` ``setup(…)`` Replaces ``setUp(…)`` ``short_description(…)`` Replaces ``shortDescription(…)`` ``teardown(…)`` Replaces ``tearDown(…)`` ``FunctionTestCase`` attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``__init__(self, test_func, set_up, tear_down, description)`` Replaces ``__init__(self, testFunc, setUp, tearDown, description)`` ``run_test(…)`` Replaces ``runTest(…)`` ``set_up(…)`` Replaces ``setUp(…)`` ``short_description(…)`` Replaces ``shortDescription(…)`` ``tear_down(…)`` Replaces ``tearDown(…)`` ``TestSuite`` attributes ~~~~~~~~~~~~~~~~~~~~~~~~ ``add_test(…)`` Replaces ``addTest(…)`` ``add_tests(…)`` Replaces ``addTests(…)`` ``count_test_cases(…)`` Replaces ``countTestCases(…)`` ``TestLoader`` attributes ~~~~~~~~~~~~~~~~~~~~~~~~~ ``sort_test_methods_using`` Replaces ``sortTestMethodsUsing`` ``suite_class`` Replaces ``suiteClass`` ``test_method_prefix`` Replaces ``testMethodPrefix`` ``get_test_case_names(self, test_case_class)`` Replaces ``getTestCaseNames(self, testCaseClass)`` ``load_tests_from_module(…)`` Replaces ``loadTestsFromModule(…)`` ``load_tests_from_name(…)`` Replaces ``loadTestsFromName(…)`` ``load_tests_from_names(…)`` Replaces ``loadTestsFromNames(…)`` ``load_tests_from_test_case(self, test_case_class)`` Replaces ``loadTestsFromTestCase(self, testCaseClass)`` ``_TextTestResult`` attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``show_all`` Replaces ``showAll`` ``add_error(…)`` Replaces ``addError(…)`` ``add_failure(…)`` Replaces ``addFailure(…)`` ``add_success(…)`` Replaces ``addSuccess(…)`` ``get_description(…)`` Replaces ``getDescription(…)`` ``print_error_list(…)`` Replaces ``printErrorList(…)`` ``print_errors(…)`` Replaces ``printErrors(…)`` ``start_test(…)`` Replaces ``startTest(…)`` ``TextTestRunner`` attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``_make_result(…)`` Replaces ``_makeResult(…)`` ``TestProgram`` attributes ~~~~~~~~~~~~~~~~~~~~~~~~~~ ``__init__(self, module, default_test, argv, test_runner, test_loader)`` Replaces ``__init__(self, module, defaultTest, argv, testRunner, testLoader)`` ``create_tests(…)`` Replaces ``createTests(…)`` ``parse_args(…)`` Replaces ``parseArgs(…)`` ``run_tests(…)`` Replaces ``runTests(…)`` ``usage_exit(…)`` Replaces ``usageExit(…)`` Rationale ========= BDFL pronouncement ------------------ The BDFL has pronounced [#vanrossum-2]_ that no API renaming is to occur in the `unittest` module. This PEP is therefore rejected. Introduction after migration to Python 3.0 ------------------------------------------ The proposal to introduce these changes along with the migration to Python 3.0 is specifically not approved by the BDFL [#vanrossum-1]_, has many detractors, and has little definite support. This PEP therefore aims for introduction no earlier than Python 3.1. Redundant names --------------- The current API, with two or in some cases three different names referencing exactly the same function, leads to an overbroad and redundant API that violates `PEP 20`_ ("there should be one, and preferably only one, obvious way to do it"). Removal of ``fail*`` names -------------------------- While there is consensus support to `remove redundant names`_ for the ``TestCase`` test methods, the issue of which set of names should be retained is controversial (it was several times characterised as "bike-shedding" [#bikeshed]_ by the BDFL and others). With good arguments made in favour of each of "retain ``assert*``" and "retain ``fail*``", this PEP resolves in favour of stated BDFL preference, and de facto community preference. Arguments in favour of retaining only the ``assert*`` names: * BDFL preference: The BDFL has stated [#vanrossum-1]_ a preference for the ``assert*`` names. * Precedent: The Python standard library currently uses the ``assert*`` names by a roughly 8:1 majority over the ``fail*`` names. (Counting unit tests in the py3k tree at 2008-07-15 [#pitrou-1]_.) An ad-hoc sampling of other projects that use `unittest` also demonstrates strong preference for use of the ``assert*`` names [#bennetts-1]_, [#seaver-1]_. * Economic: The above precedent indicates a simple economic argument [#turnbull-1]_: the majority of tests will not need their statements re-phrased, so updating in favour of them will involve less disruption and risk of error. * Positive admonition: The ``assert*`` names state the intent of how the code under test *should* behave, while the ``fail*`` names are phrased in terms of how the code *should not* behave. Arguments in favour of retaining only the ``fail*`` names: * Explicit is better than implicit: The ``fail*`` names state *what the function will do* explicitly: fail the test. With the ``assert*`` names, the action to be taken is only implicit. * Avoid false implication: The test methods do not have any necessary connection with the built-in ``assert`` statement. Even the exception raised, while it defaults to ``AssertionException``, is explicitly customisable via the documented ``failure_exception`` attribute. Choosing the ``fail*`` names avoids the false association with either of these. It has been argued [#thomas-1]_ that newcomers to `unittest` who already know what ``assert`` does can be confused by the behaviour of the ``assert*`` names. This confusion does not exist for the ``fail*`` names, which don't conflict with existing concepts. * Avoid name collision: The above confusion with ``assert`` is exacerbated by the plain-boolean test using a name of ``assert_`` (with a trailing underscore) to avoid a name collision with the built-in ``assert`` statement. The corresponding ``fail_if`` name has no such issue. PEP 8 names ----------- Although `unittest` (and its predecessor `PyUnit`) are intended to be familiar to users of other xUnit interfaces, there is no attempt at direct API compatibility since the only code that Python's `unittest` interfaces with is other Python code. The module is in the standard library and its names should all conform with `PEP 8`_. While argument was raised [#hettinger-1]_ over the length of names resulting from a simple conversion of names to multi_word_with_underscores, this PEP chooses names that are consistent in wording with the existing names. An exception was made in the case of ``setup`` and ``teardown``. The two-word form of these names was judged [#hettinger-1]_ too cumbersome compared to the new single-word form. Backwards Compatibility ======================= The names to be obsoleted should be deprecated and removed according to the schedule for modules in `PEP 4`_. While deprecated, use of the deprecated attributes should raise a ``DeprecationWarning``, with a message stating which replacement name should be used. Reference Implementation ======================== None yet. Copyright ========= This document is hereby placed in the public domain by its author. .. _PEP 4: http://www.python.org/dev/peps/pep-0004 .. _PEP 8: http://www.python.org/dev/peps/pep-0008 .. _PEP 20: http://www.python.org/dev/peps/pep-0020 .. [#bikeshed] http://www.catb.org/~esr/jargon/html/B/bikeshedding.html .. [#vanrossum-1] http://mail.python.org/pipermail/python-dev/2008-April/078485.html .. [#vanrossum-2] http://mail.python.org/pipermail/python-dev/2008-July/081263.html .. [#pitrou-1] http://mail.python.org/pipermail/python-dev/2008-July/081090.html .. [#bennetts-1] http://mail.python.org/pipermail/python-dev/2008-July/081141.html .. [#seaver-1] http://mail.python.org/pipermail/python-dev/2008-July/081166.html .. [#thomas-1] http://mail.python.org/pipermail/python-dev/2008-July/081153.html .. [#hettinger-1] http://mail.python.org/pipermail/python-dev/2008-July/081107.html .. [#turnbull-1] http://mail.python.org/pipermail/python-dev/2008-July/081175.html .. Local Variables: mode: rst coding: utf-8 End: vim: filetype=rst : _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com