Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor Loader #65

Open
wants to merge 20 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 64 additions & 50 deletions mamba/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,34 +10,31 @@

class Loader(object):
def load_examples_from(self, module):
loaded = []
example_groups = self._example_groups_for(module)
return [
self._create_example_group(klass)
for klass in self._top_level_classes_in(module)
]

for klass in example_groups:
example_group = self._create_example_group(klass)
self._add_hooks_examples_and_nested_example_groups_to(klass, example_group)
def _create_example_group(self, klass):
example_group = self._create_bare_example_group(klass)
self._add_hooks_examples_and_nested_example_groups_to(klass, example_group)

loaded.append(example_group)
return example_group

return loaded

def _example_groups_for(self, module):
return [klass for name, klass in inspect.getmembers(module, inspect.isclass) if self._is_example_group(name)]

def _is_example_group(self, class_name):
return class_name.endswith('__description')

def _create_example_group(self, klass, execution_context=None):
def _create_bare_example_group(self, klass, execution_context=None):
if '__pending' in klass.__name__:
return PendingExampleGroup(self._subject(klass), execution_context=execution_context)
return ExampleGroup(self._subject(klass), execution_context=execution_context)
return PendingExampleGroup(self._subject_of(klass), execution_context=execution_context)
return ExampleGroup(self._subject_of(klass), execution_context=execution_context)

def _subject_of(self, klass):
return getattr(
klass,
'_subject_class',
self._generate_default_subject(klass)
)

def _subject(self, example_group):
subject = getattr(example_group, '_subject_class', example_group.__name__.replace('__description', '').replace('__pending', ''))
if isinstance(subject, str):
return subject[10:]
else:
return subject
def _generate_default_subject(self, klass):
return klass.__name__.replace('__description', '').replace('__pending', '')[10:]

def _add_hooks_examples_and_nested_example_groups_to(self, klass, example_group):
self._load_hooks(klass, example_group)
Expand All @@ -49,50 +46,67 @@ def _load_hooks(self, klass, example_group):
for hook in self._hooks_in(klass):
example_group.hooks[hook.__name__].append(hook)

def _hooks_in(self, example_group):
return [method for name, method in self._methods_for(example_group) if self._is_hook(name)]
def _hooks_in(self, klass):
return [method for name, method in self._methods_in(klass) if self._is_name_of_hook(name)]

def _is_hook(self, method_name):
def _methods_in(self, klass):
return inspect.getmembers(klass, inspect.isfunction if is_python3() else inspect.ismethod)

def _is_name_of_hook(self, method_name):
return method_name.startswith('before') or method_name.startswith('after')

def _load_examples(self, klass, example_group):
for example in self._examples_in(klass):
if self._is_pending_example(example) or self._is_pending_example_group(example_group):
example_group.append(PendingExample(example))
for method in self._methods_representing_examples_in(klass):
if self._is_name_of_pending_example(method.__name__) or self._is_pending_example_group(example_group):
example_group.append(PendingExample(method))
else:
example_group.append(Example(example))

def _examples_in(self, example_group):
return [method for name, method in self._methods_for(example_group) if self._is_example(method)]
example_group.append(Example(method))

def _methods_for(self, klass):
return inspect.getmembers(klass, inspect.isfunction if is_python3() else inspect.ismethod)
def _methods_representing_examples_in(self, klass):
return [method for name, method in self._methods_in(klass) if self._is_name_of_example(name)]

def _is_example(self, method):
return method.__name__[10:].startswith('it') or self._is_pending_example(method)
def _is_name_of_example(self, name):
return name[10:].startswith('it') or self._is_name_of_pending_example(name)

def _is_pending_example(self, example):
return example.__name__[10:].startswith('_it')
def _is_name_of_pending_example(self, name):
return name[10:].startswith('_it')

def _is_pending_example_group(self, example_group):
return isinstance(example_group, PendingExampleGroup)

def _load_nested_example_groups(self, klass, example_group):
for nested in self._example_groups_for(klass):
if isinstance(example_group, PendingExampleGroup):
nested_example_group = PendingExampleGroup(self._subject(nested), execution_context=example_group.execution_context)
for nested_class in self._top_level_classes_in(klass):
if self._is_pending_example_group(example_group):
nested_example_group = PendingExampleGroup(self._subject_of(nested_class), example_group.execution_context)
else:
nested_example_group = self._create_example_group(nested, execution_context=example_group.execution_context)
nested_example_group = self._create_bare_example_group(nested_class, example_group.execution_context)

self._add_hooks_examples_and_nested_example_groups_to(nested, nested_example_group)
self._add_hooks_examples_and_nested_example_groups_to(nested_class, nested_example_group)
example_group.append(nested_example_group)

def _top_level_classes_in(self, an_object):
return [klass for name, klass in self._classes_in(an_object) if self._is_name_of_example_group(name)]

def _classes_in(self, an_object):
return inspect.getmembers(an_object, inspect.isclass)

def _is_name_of_example_group(self, name):
return name.endswith('__description')

def _load_helper_methods_to_execution_context(self, klass, execution_context):
helper_methods = [method for name, method in self._methods_for(klass) if not self._is_example(method)]
for helper_method in self._helper_methods_in(klass):
self._add_method_to_execution_context(helper_method, execution_context)

for method in helper_methods:
if is_python3():
setattr(execution_context, method.__name__, types.MethodType(method, execution_context))
else:
setattr(execution_context, method.__name__, types.MethodType(method.im_func, execution_context, execution_context.__class__))
def _helper_methods_in(self, klass):
return [method for name, method in self._methods_in(klass) if self._is_name_of_helper_method(name)]

def _is_name_of_helper_method(self, name):
return not self._is_name_of_example(name)

def _add_method_to_execution_context(self, method, execution_context):
setattr(execution_context, method.__name__, self._create_method_bound_to_object(method, execution_context))

def _create_method_bound_to_object(self, method, an_object):
if is_python3():
return types.MethodType(method, an_object)
return types.MethodType(method.im_func, an_object, an_object.__class__)