2007-01-24 22:24:01 +08:00
|
|
|
import py
|
|
|
|
defaultconftestpath = py.magic.autopath().dirpath('defaultconftest.py')
|
|
|
|
|
|
|
|
class Conftest(object):
|
|
|
|
""" the single place for accessing values and interacting
|
|
|
|
towards conftest modules from py.test objects.
|
|
|
|
|
|
|
|
Note that triggering Conftest instances to import
|
|
|
|
conftest.py files may result in added cmdline options.
|
|
|
|
XXX
|
|
|
|
"""
|
|
|
|
def __init__(self, path=None):
|
|
|
|
self._path2confmods = {}
|
|
|
|
if path is not None:
|
|
|
|
self.setinitial([path])
|
|
|
|
|
|
|
|
def setinitial(self, args):
|
|
|
|
""" return a Conftest object initialized with a path obtained
|
|
|
|
from looking at the first (usually cmdline) argument that points
|
|
|
|
to an existing file object.
|
|
|
|
XXX note: conftest files may add command line options
|
|
|
|
and we thus have no completely safe way of determining
|
|
|
|
which parts of the arguments are actually related to options.
|
|
|
|
"""
|
|
|
|
current = py.path.local()
|
|
|
|
for arg in args + [current]:
|
|
|
|
anchor = current.join(arg, abs=1)
|
|
|
|
if anchor.check(): # we found some file object
|
2007-01-27 23:40:25 +08:00
|
|
|
#print >>py.std.sys.stderr, "initializing conftest from", anchor
|
2007-01-24 22:24:01 +08:00
|
|
|
# conftest-lookups without a path actually mean
|
|
|
|
# lookups with our initial path.
|
|
|
|
self._path2confmods[None] = self.getconftestmodules(anchor)
|
|
|
|
#print " -> ", conftest._path2confmods
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
|
|
def getconftestmodules(self, path):
|
|
|
|
""" return a list of imported conftest modules for the given path. """
|
|
|
|
try:
|
|
|
|
clist = self._path2confmods[path]
|
|
|
|
except KeyError:
|
|
|
|
dp = path.dirpath()
|
|
|
|
if dp == path:
|
2007-02-04 20:29:26 +08:00
|
|
|
return [importconfig(defaultconftestpath)]
|
2007-01-24 22:24:01 +08:00
|
|
|
clist = self.getconftestmodules(dp)
|
|
|
|
conftestpath = path.join("conftest.py")
|
|
|
|
if conftestpath.check(file=1):
|
2007-02-04 20:29:26 +08:00
|
|
|
clist.append(importconfig(conftestpath))
|
2007-01-24 22:24:01 +08:00
|
|
|
self._path2confmods[path] = clist
|
|
|
|
# be defensive: avoid changes from caller side to
|
|
|
|
# affect us by always returning a copy of the actual list
|
|
|
|
return clist[:]
|
|
|
|
|
|
|
|
def rget(self, name, path=None):
|
2007-02-04 20:29:26 +08:00
|
|
|
mod, value = self.rget_with_confmod(name, path)
|
|
|
|
return value
|
|
|
|
|
|
|
|
def rget_with_confmod(self, name, path=None):
|
2007-01-24 22:24:01 +08:00
|
|
|
modules = self.getconftestmodules(path)
|
|
|
|
modules.reverse()
|
2007-01-27 22:01:45 +08:00
|
|
|
for mod in modules:
|
2007-01-24 22:24:01 +08:00
|
|
|
try:
|
2007-02-04 20:29:26 +08:00
|
|
|
return mod, getattr(mod, name)
|
2007-01-24 22:24:01 +08:00
|
|
|
except AttributeError:
|
|
|
|
continue
|
|
|
|
raise KeyError, name
|
|
|
|
|
2007-02-04 20:29:26 +08:00
|
|
|
def importconfig(configpath):
|
|
|
|
# We could have used caching here, but it's redundant since
|
|
|
|
# they're cached on path anyway, so we use it only when doing rget_path
|
|
|
|
assert configpath.check(), configpath
|
|
|
|
if not configpath.dirpath('__init__.py').check(file=1):
|
|
|
|
# HACK: we don't want any "globally" imported conftest.py,
|
|
|
|
# prone to conflicts and subtle problems
|
|
|
|
modname = str(configpath).replace('.', configpath.sep)
|
|
|
|
mod = configpath.pyimport(modname=modname)
|
|
|
|
else:
|
|
|
|
mod = configpath.pyimport()
|
|
|
|
return mod
|