Skip to content

Commit

Permalink
Add support for packages and frompackages
Browse files Browse the repository at this point in the history
  • Loading branch information
mementum committed Feb 14, 2017
1 parent 2a11ee2 commit 1146c83
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 1 deletion.
15 changes: 15 additions & 0 deletions backtrader/errors.py
Expand Up @@ -34,3 +34,18 @@ class StrategySkipError(BacktraderError):
'''Requests the platform to skip this strategy for backtesting. To be
raised during the initialization (``__init__``) phase of the instance'''
pass


class ModuleImportError(BacktraderError):
'''Raised if a class requests a module to be present to work and it cannot
be imported'''
def __init__(self, message, *args):
super(ModuleImportError, self).__init__(message)
self.args = args


class FromModuleImportError(ModuleImportError):
'''Raised if a class requests a module to be present to work and it cannot
be imported'''
def __init__(self, message, *args):
super(FromModuleImportError, self).__init__(message, *args)
50 changes: 49 additions & 1 deletion backtrader/metabase.py
Expand Up @@ -25,7 +25,8 @@
import itertools
import sys

from .utils.py3 import zip
import backtrader as bt
from .utils.py3 import zip, string_types


def findbases(kls, topclass):
Expand Down Expand Up @@ -205,21 +206,68 @@ def __new__(meta, name, bases, dct):
# (and hence "repetition")
newparams = dct.pop('params', ())

packs = 'packages'
newpackages = tuple(dct.pop(packs, ())) # remove before creation

fpacks = 'frompackages'
fnewpackages = tuple(dct.pop(fpacks, ())) # remove before creation

# Create the new class - this pulls predefined "params"
cls = super(MetaParams, meta).__new__(meta, name, bases, dct)

# Pulls the param class out of it - default is the empty class
params = getattr(cls, 'params', AutoInfoClass)

# Pulls the packages class out of it - default is the empty class
packages = tuple(getattr(cls, packs, ()))
fpackages = tuple(getattr(cls, fpacks, ()))

# get extra (to the right) base classes which have a param attribute
morebasesparams = [x.params for x in bases[1:] if hasattr(x, 'params')]

# Get extra packages, add them to the packages and put all in the class
for y in [x.packages for x in bases[1:] if hasattr(x, packs)]:
packages += tuple(y)

for y in [x.frompackages for x in bases[1:] if hasattr(x, fpacks)]:
fpackages += tuple(y)

cls.packages = packages + newpackages
cls.frompackages = fpackages + fnewpackages

# Subclass and store the newly derived params class
cls.params = params._derive(name, newparams, morebasesparams)

return cls

def donew(cls, *args, **kwargs):
clsmod = sys.modules[cls.__module__]
# import specified packages
for p in cls.packages:
if isinstance(p, (tuple, list)):
p, palias = p
else:
palias = p

pmod = __import__(p)
setattr(clsmod, palias, pmod)

# import from specified packages - the 2nd part is a string or iterable
for p, frompackage in cls.frompackages:
if isinstance(frompackage, string_types):
frompackage = (frompackage,) # make it a tuple

for fp in frompackage:
if isinstance(fp, (tuple, list)):
fp, falias = fp
else:
fp, falias = fp, fp # assumed is string

# complain "not string" without fp (unicode vs bytes)
pmod = __import__(p, fromlist=[str(fp)])
pattr = getattr(pmod, fp)
setattr(clsmod, falias, pattr)

# Create params and set the values from the kwargs
params = cls.params()
for pname, pdef in cls.params._getitems():
Expand Down

0 comments on commit 1146c83

Please sign in to comment.