/usr/share/pyshared/dingus.py is in python-dingus 0.3.4-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 | import sys
from functools import wraps
def DingusTestCase(object_under_test, exclude=None):
if isinstance(exclude, basestring):
raise ValueError("Strings not allowed for exclude. " +
"Use a list: exclude=['identifier']")
exclude = [] if exclude is None else exclude
def get_names_under_test():
module = sys.modules[object_under_test.__module__]
for name, value in module.__dict__.iteritems():
if value is object_under_test or name in exclude:
yield name
class TestCase(object):
def setup(self):
module_name = object_under_test.__module__
self._dingus_module = sys.modules[module_name]
self._dingus_replace_module_globals(self._dingus_module)
def teardown(self):
self._dingus_restore_module(self._dingus_module)
def _dingus_replace_module_globals(self, module):
old_module_dict = module.__dict__.copy()
module_keys = set(module.__dict__.iterkeys())
dunders = set(k for k in module_keys
if k.startswith('__') and k.endswith('__'))
replaced_keys = (module_keys - dunders - set(names_under_test))
for key in replaced_keys:
module.__dict__[key] = Dingus()
module.__dict__['__dingused_dict__'] = old_module_dict
def _dingus_restore_module(self, module):
old_module_dict = module.__dict__['__dingused_dict__']
module.__dict__.clear()
module.__dict__.update(old_module_dict)
names_under_test = list(get_names_under_test())
TestCase.__name__ = '%s_DingusTestCase' % '_'.join(names_under_test)
return TestCase
# These sentinels are used for argument defaults because the user might want
# to pass in None, which is different in some cases than passing nothing.
class NoReturnValue(object):
pass
class NoArgument(object):
pass
def patch(object_path, new_object=NoArgument):
module_name, attribute_name = object_path.rsplit('.', 1)
return _Patcher(module_name, attribute_name, new_object)
class _Patcher:
def __init__(self, module_name, attribute_name, new_object):
self.module_name = module_name
self.attribute_name = attribute_name
self.module = _importer(self.module_name)
if new_object is NoArgument:
full_name = '%s.%s' % (module_name, attribute_name)
self.new_object = Dingus(full_name)
else:
self.new_object = new_object
def __call__(self, fn):
@wraps(fn)
def new_fn(*args, **kwargs):
self.patch_object()
try:
return fn(*args, **kwargs)
finally:
self.restore_object()
return new_fn
def __enter__(self):
self.patch_object()
def __exit__(self, exc_type, exc_value, traceback):
self.restore_object()
def patch_object(self):
self.original_object = getattr(self.module, self.attribute_name)
setattr(self.module, self.attribute_name, self.new_object)
def restore_object(self):
setattr(self.module, self.attribute_name, self.original_object)
def isolate(object_path):
def decorator(fn):
module_name, object_name = object_path.rsplit('.', 1)
module = sys.modules[module_name]
neighbors = set(dir(module)) - set([object_name])
for neighbor in neighbors:
neighbor_path = '%s.%s' % (module_name, neighbor)
fn = patch(neighbor_path)(fn)
return fn
return decorator
def _importer(target):
components = target.split('.')
import_path = components.pop(0)
thing = __import__(import_path)
for comp in components:
import_path += ".%s" % comp
thing = _dot_lookup(thing, comp, import_path)
return thing
def _dot_lookup(thing, comp, import_path):
try:
return getattr(thing, comp)
except AttributeError:
__import__(import_path)
return getattr(thing, comp)
class DontCare(object):
pass
class Call(tuple):
def __new__(cls, name, args, kwargs, return_value):
return tuple.__new__(cls, (name, args, kwargs, return_value))
def __init__(self, *args):
self.name = self[0]
self.args = self[1]
self.kwargs = self[2]
self.return_value = self[3]
def __getnewargs__(self):
return (self.name, self.args, self.kwargs, self.return_value)
class CallList(list):
@staticmethod
def _match_args(call, args):
if not args:
return True
elif len(args) != len(call.args):
return False
else:
return all(args[i] in (DontCare, call.args[i])
for i in range(len(call.args)))
@staticmethod
def _match_kwargs(call, kwargs):
if not kwargs:
return True
elif len(kwargs) != len(call.kwargs):
return False
else:
return all(name in kwargs and kwargs[name] in (DontCare, val)
for name, val in call.kwargs.iteritems())
def one(self):
if len(self) == 1:
return self[0]
else:
return None
def once(self):
return self.one()
def __call__(self, __name=NoArgument, *args, **kwargs):
return CallList([call for call in self
if (__name is NoArgument or __name == call.name)
and self._match_args(call, args)
and self._match_kwargs(call, kwargs)])
def returner(return_value):
return Dingus(return_value=return_value)
class Dingus(object):
@property
def __enter__(self):
return self._existing_or_new_child('__enter__')
def __exit__(self, exc_type=None, exc_val=None, exc_tb=None):
if exc_type and exc_type not in self.consumed_context_manager_exceptions:
return False
else:
return True
def __init__(self,
dingus_name=None,
full_name=None,
consumed_context_manager_exceptions=None,
**kwargs):
self._parent = None
self.reset()
name = 'dingus_%i' % id(self) if dingus_name is None else dingus_name
full_name = name if full_name is None else full_name
self._short_name = name
self._full_name = full_name
self.__name__ = name
self._full_name = full_name
self.consumed_context_manager_exceptions = (
consumed_context_manager_exceptions or [])
for attr_name, attr_value in kwargs.iteritems():
if attr_name.endswith('__returns'):
attr_name = attr_name.replace('__returns', '')
returner = self._create_child(attr_name)
returner.return_value = attr_value
setattr(self, attr_name, returner)
else:
setattr(self, attr_name, attr_value)
self._replace_init_method()
@classmethod
def many(cls, count):
return tuple(cls() for _ in range(count))
def _fake_init(self, *args, **kwargs):
return self.__getattr__('__init__')(*args, **kwargs)
def _replace_init_method(self):
self.__init__ = self._fake_init
def _create_child(self, name):
separator = ('' if (name.startswith('()') or name.startswith('['))
else '.')
full_name = self._full_name + separator + name
child = self.__class__(name, full_name)
child._parent = self
return child
def reset(self):
self._return_value = NoReturnValue
self.calls = CallList()
self._children = {}
def _get_return_value(self):
if self._return_value is NoReturnValue:
self._return_value = self._create_child('()')
return self._return_value
def _set_return_value(self, value):
self._return_value = value
return_value = property(_get_return_value, _set_return_value)
def __call__(self, *args, **kwargs):
self._log_call('()', args, kwargs, self.return_value)
if self._parent:
self._parent._log_call(self._short_name,
args,
kwargs,
self.return_value)
return self.return_value
def _log_call(self, name, args, kwargs, return_value):
self.calls.append(Call(name, args, kwargs, return_value))
def _should_ignore_attribute(self, name):
return name in ['__pyobjc_object__', '__getnewargs__']
def __getstate__(self):
# Python cannot pickle a instancemethod
# http://bugs.python.org/issue558238
return [ (attr, value) for attr, value in self.__dict__.items() if attr != "__init__"]
def __setstate__(self, state):
self.__dict__.update(state)
self._replace_init_method()
def _existing_or_new_child(self, child_name, default_value=NoArgument):
if child_name not in self._children:
value = (self._create_child(child_name)
if default_value is NoArgument
else default_value)
self._children[child_name] = value
return self._children[child_name]
def _remove_child_if_exists(self, child_name):
if child_name in self._children:
del self._children[child_name]
def __getattr__(self, name):
if self._should_ignore_attribute(name):
raise AttributeError(name)
return self._existing_or_new_child(name)
def __delattr__(self, name):
self._log_call('__delattr__', (name,), {}, None)
def __getitem__(self, index):
child_name = '[%s]' % (index,)
return_value = self._existing_or_new_child(child_name)
self._log_call('__getitem__', (index,), {}, return_value)
return return_value
def __setitem__(self, index, value):
child_name = '[%s]' % (index,)
self._log_call('__setitem__', (index, value), {}, None)
self._remove_child_if_exists(child_name)
self._existing_or_new_child(child_name, value)
def _create_infix_operator(name):
def operator_fn(self, other):
return_value = self._existing_or_new_child(name)
self._log_call(name, (other,), {}, return_value)
return return_value
operator_fn.__name__ = name
return operator_fn
_BASE_OPERATOR_NAMES = ['add', 'and', 'div', 'lshift', 'mod', 'mul', 'or',
'pow', 'rshift', 'sub', 'xor']
def _infix_operator_names(base_operator_names):
# This function has to have base_operator_names passed in because
# Python's scoping rules prevent it from seeing the class-level
# _BASE_OPERATOR_NAMES.
reverse_operator_names = ['r%s' % name for name in base_operator_names]
for operator_name in base_operator_names + reverse_operator_names:
operator_fn_name = '__%s__' % operator_name
yield operator_fn_name
# Define each infix operator
for operator_fn_name in _infix_operator_names(_BASE_OPERATOR_NAMES):
exec('%s = _create_infix_operator("%s")' % (operator_fn_name,
operator_fn_name))
def _augmented_operator_names(base_operator_names):
# Augmented operators are things like +=. They behavior differently
# than normal infix operators because they return self instead of a
# new object.
return ['__i%s__' % operator_name
for operator_name in base_operator_names]
def _create_augmented_operator(name):
def operator_fn(self, other):
return_value = self
self._log_call(name, (other,), {}, return_value)
return return_value
operator_fn.__name__ = name
return operator_fn
# Define each augmenting operator
for operator_fn_name in _augmented_operator_names(_BASE_OPERATOR_NAMES):
exec('%s = _create_augmented_operator("%s")' % (operator_fn_name,
operator_fn_name))
def __str__(self):
return '<Dingus %s>' % self._full_name
__repr__ = __str__
def __len__(self):
return 1
def __iter__(self):
return iter([self._existing_or_new_child('__iter__')])
# We don't want to define __deepcopy__ at all. If there isn't one, deepcopy
# will clone the whole object, which is what we want.
__deepcopy__ = None
def exception_raiser(exception):
def raise_exception(*args, **kwargs):
raise exception
return raise_exception
|