* [gentoo-commits] proj/pms-test-suite:master commit in: pmstestsuite/pm/, pmstestsuite/library/, pmstestsuite/, pmstestsuite/repository/
@ 2011-07-10 10:12 Michał Górny
0 siblings, 0 replies; only message in thread
From: Michał Górny @ 2011-07-10 10:12 UTC (permalink / raw
To: gentoo-commits
commit: a29cb26877a18d057a80d293a48b5ce2e5a733db
Author: Michał Górny <mgorny <AT> gentoo <DOT> org>
AuthorDate: Sun Jul 10 10:13:28 2011 +0000
Commit: Michał Górny <mgorny <AT> gentoo <DOT> org>
CommitDate: Sun Jul 10 10:13:28 2011 +0000
URL: http://git.overlays.gentoo.org/gitweb/?p=proj/pms-test-suite.git;a=commit;h=a29cb268
Reformat docs for epydoc.
---
pmstestsuite/cli.py | 26 +++---
pmstestsuite/library/__init__.py | 46 ++++++++---
pmstestsuite/library/case.py | 95 +++++++++++++++--------
pmstestsuite/library/depend_case.py | 19 ++++-
pmstestsuite/pm/__init__.py | 140 ++++++++++++++++++++++----------
pmstestsuite/pm/pkgcorepm.py | 1 -
pmstestsuite/pm/portagepm.py | 1 -
pmstestsuite/repository/__init__.py | 42 ++++++++---
pmstestsuite/repository/pms_eclass.py | 7 ++-
9 files changed, 260 insertions(+), 117 deletions(-)
diff --git a/pmstestsuite/cli.py b/pmstestsuite/cli.py
index 4d309f8..518d826 100644
--- a/pmstestsuite/cli.py
+++ b/pmstestsuite/cli.py
@@ -15,24 +15,23 @@ from pmstestsuite.pm import get_package_managers
class PMSTestSuiteCLI(object):
"""
- A class encapsulating CLI routines used by the PMS Test Suite.
-
- Properties:
- 1) set during __init__():
- - optparser (OptionParser);
- 2) set during start():
- - library (TestLibrary),
- - pm (PackageManager),
- - repository (EbuildRepository).
+ A class encapsulating the CLI routines used by the PMS Test Suite.
>>> cli = PMSTestSuiteCLI()
+
+ @ivar optparser: the option parser
+ @type optparser: optparse.OptionParser
+ @ivar library: the test library
+ @type library: L{TestLibrary}
+ @ivar pm: the active package manager
+ @type pm: L{PackageManager}
+ @ivar repository: the active ebuild repository
+ @type repository: L{EbuildRepository}
"""
def __init__(self):
"""
Initialize the class. Set the option parser up.
-
- <prog> - program name for optparse output (argv[0])
"""
opt = OptionParser(version = PV)
@@ -68,7 +67,10 @@ class PMSTestSuiteCLI(object):
Initialize the program. Parse command-line args. Instantiate classes
encapsulating the Package Manager, test library and repository.
- <args> - command line args (argv[1:])
+ @param prog: the program name (C{argv[0]})
+ @type prog: string
+ @param args: command line arguments (C{argv[1:]})
+ @type args: strings
"""
opt = self.optparser
opt.prog = os.path.basename(prog)
diff --git a/pmstestsuite/library/__init__.py b/pmstestsuite/library/__init__.py
index d65958f..c286d22 100644
--- a/pmstestsuite/library/__init__.py
+++ b/pmstestsuite/library/__init__.py
@@ -19,21 +19,38 @@
'# Copyright 1999...inherit pms-test...die...'
"""
+from abc import abstractproperty
+from gentoopm.util import ABCObject
+
from pmstestsuite.library.case import TestCase
-class TestLibrary(object):
- """ Base class for a test library. """
+class TestLibrary(ABCObject):
+ """
+ Base class for a test library.
+
+ @ivar tests: cache of instantiated tests
+ @type tests: list(L{TestCase})
+ """
tests = None
+
+ @abstractproperty
+ def test_names(self):
+ """
+ Names of test classes in the library, including a module path relative
+ to the library root.
+
+ @type: iterable(string)
+ """
def __iter__(self):
"""
Iterate over all the tests in a test library, loading its modules
- as necessary. Uses <self.test_names> to get the module names.
+ as necessary.
- Returns an iterator over TestCase subclass instances or raises one
- of the following exceptions:
- - ImportError if submodule import fails.
+ @return: an iterable over instantiated test cases
+ @rtype: generator(L{TestCase})
+ @raise ImportError: if submodule import fails.
"""
if self.tests is not None:
@@ -87,13 +104,16 @@ class TestLibrary(object):
def load_library(name, **kwargs):
"""
- Try to load a test library <name>. Instiantiate the first TestLibrary
- subclass found there. Pass kwargs to the __init__() function.
-
- Returns a new TestLibrary subclass instance or raises one of the following
- exceptions:
- - ImportError if module import fails,
- - TypeError if no matching class is found.
+ Try to load a test library. Instiantiate the first TestLibrary subclass
+ found there.
+
+ @param name: the test library name
+ @type name: string
+ @param kwargs: keyword arguments to pass to the library constructor
+ @return: an instantiated test library
+ @rtype: L{TestLibrary}
+ @raise ImportError: if module import fails
+ @raise TypeError: if no matching class is found in the module
"""
modname = 'pmstestsuite.library.%s' % name
diff --git a/pmstestsuite/library/case.py b/pmstestsuite/library/case.py
index 4d5d8fe..18490ec 100644
--- a/pmstestsuite/library/case.py
+++ b/pmstestsuite/library/case.py
@@ -3,6 +3,7 @@
# Released under the terms of the 2-clause BSD license.
import copy, random, re
+from gentoopm.util import ABCObject
from abc import ABCMeta, abstractmethod, abstractproperty
@@ -13,6 +14,8 @@ phase_func_names = [
'pkg_preinst', 'pkg_postinst'
]
+""" Names of all phase functions supported in EAPIs. """
+
ebuild_header = '''# Copyright 1999-2011 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $
@@ -23,11 +26,13 @@ inherit %s
'''
+""" A common ebuild header. """
+
pn_re = re.compile('([^A-Z])([A-Z])')
def cleanup_test_case_name(classname):
"""
- Create the ebuild PN from <classname>.
+ Create the ebuild PN from classname.
>>> cleanup_test_case_name('Testzor')
'testzor'
@@ -39,15 +44,23 @@ def cleanup_test_case_name(classname):
'very-random-camel-case'
>>> cleanup_test_case_name('RDependTest')
'rdepend'
+
+ @param classname: the class name to clean up
+ @type classname: string
"""
if classname.endswith('Test'):
classname = classname[:-4]
return pn_re.sub('\\1-\\2', classname).lower()
-class TestCase(object):
- """ Base class for a test case. """
- __metaclass__ = ABCMeta
+class TestCase(ABCObject):
+ """
+ Base class for a test case.
+
+ @ivar _finalized: has the case initialization been finished yet?
+ Set by L{_finalize()}.
+ @type _finalized: bool
+ """
_finalized = False
@@ -62,23 +75,30 @@ class TestCase(object):
def get_output_files(self):
"""
Get a dict of files to output in the repository for the test case.
-
- Returns a dict with keys being filenames relative to the repository root
- and associated values evaluating to a file contents (as strings).
+
+ @return: a dict where keys are file paths (relative to the repository
+ root), and values evaluate to file contents
+ @rtype: dict (string -> stringifiable)
"""
pass
@abstractmethod
def clean(self, pm):
"""
- Schedule cleaning the test using PackageManager instance <pm>.
+ Schedule cleaning the test.
+
+ @param pm: the package manager instance
+ @type pm: L{PackageManager}
"""
pass
@abstractmethod
def start(self, pm):
"""
- Schedule starting the test using PackageManager instance <pm>.
+ Schedule starting the test.
+
+ @param pm: the package manager instance
+ @type pm: L{PackageManager}
"""
pass
@@ -86,27 +106,32 @@ class TestCase(object):
def check_result(self, pm):
"""
Check the correctness of the result of test execution.
- <pm> points to the current PackageManager instance.
- Shall return True if the results indicate that the test succeeded,
- False otherwise.
+ @param pm: the package manager instance
+ @type pm: L{PackageManager}
+
+ @return: True if the test succeeded, False otherwise
+ @rtype: bool
"""
pass
class EbuildTestCase(TestCase):
"""
Test case using a single ebuild (per EAPI).
+
+ The __init__() function is going to clone (deepcopy()) all the instance
+ variables to allow modifying them easily.
- Properties:
- - ebuild_vars - additional global variables (a dict of strings),
- - expect_failure - if set to False (the default), the test is supposed
+ @ivar ebuild_vars: additional global variables
+ @type ebuild_vars: dict (string -> string)
+ @ivar expect_failure: if set to False (the default), the test is supposed
to merge successfully. Otherwise, the test ebuild is supposed to fail
- to merge (die),
- - inherits - additional eclasses to inherit (a list of strings),
- - phase_funcs - phase function contents (a dict of lists).
-
- The __init__() function is going to clone (deepcopy()) all the above
- properties to allow modifying instance variables easily.
+ to merge (die)
+ @type expect_failure: bool
+ @ivar inherits: additional eclasses to inherit
+ @type inherits: list (string)
+ @ivar phase_funcs: phase function contents
+ @type phase_funcs: dict (string -> list(string))
"""
ebuild_vars = {}
@@ -119,6 +144,11 @@ class EbuildTestCase(TestCase):
"""
Evaluate and return the value of a property when passed a property
object, or return the passed value otherwise.
+
+ @param prop_or_obj: the object to process
+ @type prop_or_obj: property/object
+ @return: value of the property
+ @rtype: object
"""
if isinstance(prop_or_obj, property):
@@ -134,6 +164,8 @@ class EbuildTestCase(TestCase):
For example, if a feature is required in EAPI 3+ and optional
in earlier EAPIs, this variable should contain (3,4).
+
+ @type: iterable
"""
return (0, 1, 2, 3, 4)
@@ -145,6 +177,8 @@ class EbuildTestCase(TestCase):
a change of behaviour occurs.
When unset, defaults to a random element of .supported_eapis().
+
+ @type: iterable
"""
return (random.choice(cls._eval_prop(cls.supported_eapis)),)
@@ -154,7 +188,8 @@ class EbuildTestCase(TestCase):
Instantiate the test case for all relevant EAPIs. If in thorough
mode, assume all supported EAPIs are relevant.
- Returns an iterator over a list of test case instances.
+ @return: an iterable over test case instances
+ @rtype: generator(L{EbuildTestCase})
"""
if thorough:
@@ -202,7 +237,12 @@ class EbuildTestCase(TestCase):
return '%s (%s)' % (self.p, self._stripped_docstring)
def __init__(self, eapi):
- """ Instiantate the test case for a particular EAPI. """
+ """
+ Instiantate the test case for a particular EAPI.
+
+ @param eapi: the EAPI
+ @type eapi: string
+ """
self.eapi = eapi
for v in ('ebuild_vars', 'inherits', 'phase_funcs'):
@@ -216,12 +256,6 @@ class EbuildTestCase(TestCase):
'm68k ~mips ppc ppc64 s390 sh sparc x86'
def get_output_files(self):
- """
- Get a dict of files to output in the repository for the test case.
-
- Returns a dict with keys being filenames relative to the repository root
- and associated values being classes evaluating to the file contents.
- """
class EbuildTestCaseEbuildFile(object):
""" Lazy ebuild contents evaluator for EbuildTestCase. """
def __init__(self, parent):
@@ -266,9 +300,6 @@ class EbuildTestCase(TestCase):
"""
Check the correctness of the result of test execution. By default,
checks whether the ebuild was actually merged.
-
- Returns True if the results indicate that the test succeeded, False
- otherwise.
"""
merged = self.atom(pm) in pm.installed
diff --git a/pmstestsuite/library/depend_case.py b/pmstestsuite/library/depend_case.py
index a9a34f6..6a6afc3 100644
--- a/pmstestsuite/library/depend_case.py
+++ b/pmstestsuite/library/depend_case.py
@@ -10,13 +10,21 @@ class EbuildDependencyTestCase(EbuildTestCase):
resolution.
In order to perform a dependency test, please:
- 1) create EbuildTestCase subclasses for the dependencies like usual,
- 2) create EbuildDependencyTestCase and refer to the classes created above in
- depend_classes or rdepend_classes.
+
+ 1. create EbuildTestCase subclasses for the dependencies like usual,
+ 2. create EbuildDependencyTestCase and refer to the classes created
+ above in depend_classes or rdepend_classes.
The class is going to set up all ebuilds, DEPEND and RDEPEND automagically.
However, you need to provide phase functions to perform the actual
dependency test (i.e. check whether the dependency was merged successfully).
+
+ @cvar depend_classes: classes for DEPEND generation
+ @type depend_classes: iterable(L{EbuildTestCase})
+ @cvar rdepend_classes: classes for RDEPEND generation
+ @type rdepend_classes: iterable(L{EbuildTestCase})
+ @cvar pdepend_classes: classes for PDEPEND generation
+ @type pdepend_classes: iterable(L{EbuildTestCase})
"""
depend_classes = []
@@ -24,6 +32,11 @@ class EbuildDependencyTestCase(EbuildTestCase):
pdepend_classes = []
def __init__(self, eapi):
+ """
+ Instantiate the dependency test case and dependant sub-cases. Set
+ C{DEPEND}, C{RDEPEND} and C{PDEPEND}.
+ """
+
EbuildTestCase.__init__(self, eapi)
self.dependant_ebuilds = []
diff --git a/pmstestsuite/pm/__init__.py b/pmstestsuite/pm/__init__.py
index 26675d0..1e1d50e 100644
--- a/pmstestsuite/pm/__init__.py
+++ b/pmstestsuite/pm/__init__.py
@@ -34,44 +34,53 @@ class PackageManager(ABCObject):
@abstractproperty
def name(self):
- """ Human-readable, short PM name (used in option values). """
- pass
-
- @property
- def failure_nonfatal(self):
"""
- A bool stating whether the package manager will treat failures
- as non-fatal to the overall merge process (if it will continue merging
- when one of the ebuilds fail, aka --keep-going).
+ Human-readable, short PM name (used in option values).
+
+ @type: string
"""
- return False
+ pass
@classmethod
def is_available(cls):
"""
Check whether a particular PM is installed and executable.
- Returns True if the PM is available, False otherwise.
+ @return: True if the PM is available, False otherwise.
+ @rtype: bool
"""
return True
@abstractmethod
def remanifest(self, paths):
- """ Regenerate Manifests in given <paths> (should be iterable). """
+ """
+ Regenerate Manifests in paths.
+
+ @param paths: directory names to regenerate manifests in
+ @type paths: iterable(string)
+ """
pass
def append_repository(self, repo):
"""
- Append the repository <repo> (EbuildRepository) to PM's list of repos.
+ Append the repository to the PM's list of repos.
+
+ @param repo: the repository to append
+ @type repo: L{EbuildRepository}
+ @raise NotImplementedError: if a particular PM doesn't support
+ appending repos
"""
self.repo_paths.append(repo.path)
def get_repository(self, name):
"""
- Get repository by name, using the PM's repository list.
+ Get a repository by name, using the PM's repository list.
- Returns EbuildRepository instance or raises KeyError when no repository
- with such name exists.
+ @param name: name to look up
+ @type name: string
+ @return: a repository instance
+ @rtype: L{EbuildRepository}
+ @raise KeyError: when no repository with matching name exists
"""
r = self.repositories[name].path
@@ -104,14 +113,20 @@ class PackageManager(ABCObject):
def merge(self, cpvs):
"""
- Queue merging <cpvs> (either a list or a string).
+ Queue merging CPVs.
+
+ @param cpvs: CPVs to merge
+ @type cpvs: string/list(string)
"""
self.op = PackageManagerOps.merge
self._append_cpvs(cpvs)
def unmerge(self, cpvs):
"""
- Queue unmerging <cpvs> (either a list or a string).
+ Queue unmerging CPVs.
+
+ @param cpvs: CPVs to unmerge
+ @type cpvs: string/list(string)
"""
self.op = PackageManagerOps.unmerge
self._append_cpvs(cpvs)
@@ -119,14 +134,26 @@ class PackageManager(ABCObject):
@abstractmethod
def _spawn_merge(self, pkgs):
"""
- Spawn PM to perform merge of <pkgs>. Returns a subprocess.
+ Spawn PM to perform the merge of packages.
+
+ @param pkgs: packages to merge
+ @type pkgs: iterable(string)
+
+ @return: the merging subprocess
+ @rtype: C{subprocess.Popen}
"""
pass
@abstractmethod
def _spawn_unmerge(self, pkgs):
"""
- Spawn PM to perform unmerge of <pkgs>. Returns a subprocess.
+ Spawn PM to perform unmerge of packages.
+
+ @param pkgs: packages to merge
+ @type pkgs: iterable(string)
+
+ @return: the merging subprocess
+ @rtype: C{subprocess.Popen}
"""
pass
@@ -146,15 +173,20 @@ class PackageManager(ABCObject):
"""
Return whether PM has any pending actions (i.e. packages
to merge/unmerge).
+
+ @type: bool
"""
return bool(self.pkg_queue)
def commit(self, callback):
"""
Perform queued operations in the background (using glib), starting PM
- multiple times if necessary. Call <callback> when done.
+ multiple times if necessary. Call callback when done.
If PM has no pending actions, the callback will be called immediately.
+
+ @param callback: function to call when done
+ @type callback: func()
"""
if not self.has_pending_actions:
@@ -185,8 +217,51 @@ class NonAvailPM(object):
def is_available(self):
return False
+class PMWrapper(object):
+ """ A wrapper class which stringifies into a name of particular PM. """
+ def __init__(self, pmclass):
+ """
+ Instantiate the wrapper for a PM class.
+
+ @param pmclass: the PM class
+ @type pmclass: class(L{PackageManager})
+ """
+ self._pmclass = pmclass
+
+ @property
+ def name(self):
+ """
+ The name of associated PM.
+
+ @type: string
+ """
+ return self._pmclass.name
+
+ def __str__(self):
+ """ Return the human-readable name of associated PM. """
+ if not self._pmclass.is_available():
+ return '(%s)' % self._pmclass.name
+ return self._pmclass.name
+
+ def inst(self):
+ """
+ Instantiate the associated PM.
+
+ @return: instantiated PM
+ @rtype: L{PackageManager}
+ """
+ if not self._pmclass.is_available():
+ raise Exception('PM is not available! Please consider installing %s.'
+ % self._pmclass.pkg)
+ return self._pmclass()
+
def get_package_managers():
- """ Return the list of supported Package Managers. """
+ """
+ Return the list of supported Package Managers.
+
+ @return: supported Package Managers
+ @rtype: L{PMWrapper}
+ """
try:
from pmstestsuite.pm.portagepm import PortagePM
@@ -201,28 +276,5 @@ def get_package_managers():
except ImportError:
PaludisPM = NonAvailPM('paludis', 'sys-apps/paludis[python]')
- class PMWrapper(object):
- """ A wrapper class which stringifies into a name of particular PM. """
- def __init__(self, pmclass):
- """ Instantiate the wrapper for PM class <pmclass>. """
- self._pmclass = pmclass
-
- @property
- def name(self):
- """ The name of associated PM. """
- return self._pmclass.name
-
- def __str__(self):
- """ Return the human-readable name of associated PM. """
- if not self._pmclass.is_available():
- return '(%s)' % self._pmclass.name
- return self._pmclass.name
-
- def inst(self):
- """ Instantiate the associated PM. """
- if not self._pmclass.is_available():
- raise Exception('PM is not available! Please consider installing %s.'
- % self._pmclass.pkg)
- return self._pmclass()
return [PMWrapper(x) for x in (PortagePM, PkgCorePM, PaludisPM)]
diff --git a/pmstestsuite/pm/pkgcorepm.py b/pmstestsuite/pm/pkgcorepm.py
index 64622dd..16da52e 100644
--- a/pmstestsuite/pm/pkgcorepm.py
+++ b/pmstestsuite/pm/pkgcorepm.py
@@ -18,7 +18,6 @@ class PkgCorePM(_PkgCorePM, PackageManager):
A class implementing the interfaces to the pkgcore PM.
"""
name = 'pkgcore'
- failure_nonfatal = False
common_pmerge_opts = ['--oneshot']
diff --git a/pmstestsuite/pm/portagepm.py b/pmstestsuite/pm/portagepm.py
index 21036a0..a33f24e 100644
--- a/pmstestsuite/pm/portagepm.py
+++ b/pmstestsuite/pm/portagepm.py
@@ -16,7 +16,6 @@ from pmstestsuite.pm import PackageManager
class PortagePM(_PortagePM, PackageManager):
""" A class implementing the interfaces to the Portage PM. """
name = 'portage'
- failure_nonfatal = True
common_emerge_opts = ['--ask', 'n', '--keep-going', '--oneshot']
diff --git a/pmstestsuite/repository/__init__.py b/pmstestsuite/repository/__init__.py
index 52a60de..fa059ef 100644
--- a/pmstestsuite/repository/__init__.py
+++ b/pmstestsuite/repository/__init__.py
@@ -15,12 +15,12 @@ class EbuildRepository(object):
def __init__(self, path):
"""
- Instantiate a new EbuildRepository for repository held in <path>. Read
- the repository name.
+ Instantiate a new EbuildRepository. Read the repository name.
- Possible exceptions:
- - IOError for repo_name file operations,
- - ValueError if repo_name doesn't contain a valid name.
+ @param path: path to the repository
+ @type path: string
+ @raise IOError: for repo_name file operations
+ @raise ValueError: if repo_name contents are invalid
"""
self.path = path
@@ -49,7 +49,12 @@ class EbuildRepository(object):
return tail
def write_files(self, files):
- """ Write files from files dict to the repository. """
+ """
+ Write files to the repository.
+
+ @param files: a dict, as returned by L{library.case.TestCase.get_output_files()}
+ @type files: dict(string -> stringifiable)
+ """
newcats = set()
for fn in files:
cat = self.get_category_from_path(fn)
@@ -67,7 +72,14 @@ class EbuildRepository(object):
f.close()
def remanifest(self, files, pm):
- """ Remanifest files from <files> dict using <pm>. """
+ """
+ Remanifest files in repository.
+
+ @param files: filenames in the repository
+ @type files: iterable(string)
+ @param pm: the package manager instance
+ @type pm: L{PackageManager}
+ """
dirs = set()
for fn in files:
cat = self.get_category_from_path(fn)
@@ -77,8 +89,13 @@ class EbuildRepository(object):
def add_categories(self, cats, files):
"""
- Add categories in <cats> to profiles/categories. Update
- the profiles/categories file in <files> dict.
+ Add categories in to profiles/categories. Update
+ the profiles/categories file in C{files}.
+
+ @param cats: categories to add
+ @type cats: list(string)
+ @param files: the files dict
+ @type files: dict(string -> stringifiable)
"""
# XXX: profiles/categories can contain new categories already
# and they may not be in self.categories
@@ -94,7 +111,12 @@ class NewEbuildRepository(EbuildRepository):
def __init__(self, path, repo_name):
"""
- Create a new ebuild repository in <path>. Name it <repo_name>.
+ Create a new ebuild repository in C{path}. Name it C{repo_name}.
+
+ @param path: path to the repository
+ @type path: string
+ @param repo_name: the new repository name
+ @type repo_name: string
"""
rnpath = os.path.join(path, 'profiles', 'repo_name')
dirpath = os.path.dirname(rnpath)
diff --git a/pmstestsuite/repository/pms_eclass.py b/pmstestsuite/repository/pms_eclass.py
index 1393c2d..99cbc5e 100644
--- a/pmstestsuite/repository/pms_eclass.py
+++ b/pmstestsuite/repository/pms_eclass.py
@@ -20,7 +20,12 @@ S=${WORKDIR}
"""
def get_common_eclass_files():
- """ Return a EbuildRepository.write_files()-dict for the eclass. """
+ """
+ Return a file-dict for the eclass.
+
+ @return: file-dict with the eclass contents
+ @rtype: dict(string -> stringifiable)
+ """
return {
os.path.join('eclass', 'pms-test.eclass'): eclass_contents
}
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2011-07-10 10:12 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-07-10 10:12 [gentoo-commits] proj/pms-test-suite:master commit in: pmstestsuite/pm/, pmstestsuite/library/, pmstestsuite/, pmstestsuite/repository/ Michał Górny
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox