[pypy-dev] "unit" definition

Armin Rigo arigo at tunes.org
Sun Mar 9 19:33:16 CET 2003


Hello everybody,

Here is a proposal for organizing our files and particularly putting them in
relation.  As the Python tests are "unit tests" I suggest the name "unit" for
a body of work composed of a couple of related files.  A unit is roughly
something as big as a Python module, but could also be used for something like
built-in types.  For example:

* 'Builtins module' unit:
      module/test/test_builtin.py
      CPython's original unit test file
      module/builtin.py
      module/builtin_app.py
      maybe CPython's __builtin__ module for the interface (docstrings...)

* 'Integer object' unit:
      objspace/std/test/test_integer.py
      objspace/std/test/test_intobject.py
      objspace/std/intobject.py
      objspace/std/intobject_app.py

A unit is something explicitely defined somewhere.  It starts abstractedly,
like with only the tests and the interface of the module (function signatures,
docstrings), and it is later "completed", i.e. (possibly incrementially)
implemented, with new implementation-specific tests and docs.

Example assuming Python syntax, using subclassing for "completing":


class BuiltinsModule(pypy.unit.ModuleUnit):
    "Expected interface for the Python __builtin__ module."
    modulename = "__builtin__"
    test1 = pypy.unit.Test("module/test/test_builtin.py")
    rawinterface = pypy.unit.InterfaceFromCPython("__builtin__")

#...and possibly somewhere else...

class MyBuiltins(path.to.the.above.BuiltinsModule):
    impl     = pypy.unit.RPythonImplementation("./my_builtin.py")
    implapp  = pypy.unit.PurePythonImplementation("./my_builtin_app.py")
    impltest = pypy.unit.Test("./test/test_my_builtin.py")
    maintainer = "arigo"

# some tests are known to fail right now
# (the following line is done with a __get__ method on pypy.unit.Test
#  so that we can refer to MyBuiltins' status of test1)
MyBuiltins.test1.known_failing += ['test_zip', 'test_unichr']

# some functions I have not implemented right now
MyBuiltins.rawinterface.known_missing += ['filter', 'reduce']

# Note that the base BuiltinsModule class has no implementation,
# hence tests won't be tested directly on it.
# Also note that there are only a couple of magic attribute names,
# like 'modulename' and 'maintainer'; all the pypy.unit.Xxx()
# instances can be found by enumerating all attributes.


The purpose of the classes of pypy.unit is to define the "roles" that each
file can assume within that unit.  They contains the magic to collect the data
together when we actually want to run the tests or pypy itself.  For example,
RPythonImplementation would search for all functions defined in the specified
file and insert them as "built-in function objects" into the proper
application-level module (or maybe not all the functions, but only the ones
specially tagged, or only the ones that are said to be part of the module
interface).

Instead of the above Python syntax for the definition of units, it could also
be done with a dedicated syntax; here XML:

module/builtinsmodule.xml:
  <unit kind="Module">
    <modulename>__builtin__</modulename>
    <test id="test1">module/test/test_builtin.py</test>
    <interface id="raw" source="CPython">__builtin__</interface>
  </unit>

module/arigo/mybuiltins.xml:
  <unit extends="module/builtinsmodule.xml">
    <doc>blah blah blah</doc>
    <implementation lang="RPython">./my_builtins.py</implementation>
    <implementation lang="PurePython">./my_builtins_app.py</implementation>
    <test>./test/test_my_builtins.py</test>
    <maintainer>arigo</maintainer>
    <status>
      <failing test_id="test1">
        test_zip
        test_unichr
      </failing>
      <missing interface_id="raw">
        filter
        reduce
      </missing>
    </status>
  </unit>

Not too bad either, althought having the power of the Python language to
express things like 'known_failing += [...]' is more flexible.  Opinions?

Opinions on the whole idea are welcome too, of course!

As you might have noticed I have located mybuiltins.xml in "module/arigo/",
following Laura's idea of separating our in-development files from the main
ones.  I have not specified here anything about the actual "release" of the
files, i.e. the process of moving them from these per-user subdirectories into
the mainstream "module/".  For now I'd say it could be as easy as moving up
the .xml file and the files it links to, and that we'll see later if we need
to agree on a more precise policy for that.  Also note that contributing a
test file that you expect to work on any implementation of a module means just
adding a line in the (base) unit corresponding to the empty module interface.

We should then precisely define the pypy.unit role classes, e.g. how Test()
files are called, what function signatures RPythonImplementation() expect
(including how to do the PyArg_ParseTuple() trick more declaratively), and how
interfaces and possibly doc files are written.  We also probably need another
kind of implementation, like LibraryImplementation, a file containing just
ctypes-like declarations of library function calls (e.g. for the posix
module).  I hope that this could give the frame that everybody is waiting for
to start the actual work!


A bientôt,

Armin.



More information about the Pypy-dev mailing list