Files
catalyst/zipline/utils/final.py
T
Joe Jevnik bc0b117dc9 MAINT: make the data loading apis more consistent.
Changes BcolzDailyBarWriter to not be an abc, data is passed as an
iterator of (sid, dataframe) pairs to the write method.

Changes the AssetsDBWriter to be a single class which accepts an engine
at construction time and has a `write` method for writing dataframes for
the various tables. We no longer support writing the various other data
types, callers should coerce their data into a dataframe themselves. See
zipline.assets.synthetic for some helpers to do this.

Adds many new fixtures and updates some existing fixtures to use the new
ones:

WithDefaultDateBounds
  A fixture that provides the suite a START_DATE and END_DATE. This is
  meant to make it easy for other fixtures to synchronize their date
  ranges without depending on eachother in strange ways. For example,
  WithBcolzMinuteBarReader and WithBcolzDailyBarReader by default should
  both have data for the same dates, so they may use depend on
  WithDefaultDates without forcing a dependency between them.

WithTmpDir, WithInstanceTmpDir
  Provides the suite or individual test case a temporary directory.

WithBcolzDailyBarReader
  Provides the suite a BcolzDailyBarReader which reads from bcolz data
  written to a temporary directory. The data will be read from
  dataframes and then converted to bcolz files with
  BcolzDailyBarWriter.write

WithBcolzDailyBarReaderFromCSVs
  Provides the suite a BcolzDailyBarReader which reads from bcolz data
  written to a temporary directory. The data will be read from a
  collection of CSV files and then converted into the bcolz data through
  BcolzDailyBarWriter.write_csvs

WithBcolzMinuteBarReader
  Provides the suite a BcolzMinuteBarReader which reads from bcolz data
  written to a temporary directory. The data will be read from
  dataframes and then converted to bcolz files with
  BcolzMinuteBarWriter.write

WithAdjustmentReader
  Provides the suite a SQLiteAdjustmentReader which reads from an in
  memory sqlite database. The data will be read from dataframes and then
  converted into sqlite with SQLiteAdjustmentWriter.write

WithDataPortal
  Provides each test case a DataPortal object with data from temporary
  resources.
2016-04-15 23:46:10 -04:00

124 lines
3.8 KiB
Python

from abc import ABCMeta, abstractmethod
from six import with_metaclass, iteritems
# Consistent error to be thrown in various cases regarding overriding
# `final` attributes.
_type_error = TypeError('Cannot override final attribute')
def bases_mro(bases):
"""
Yield classes in the order that methods should be looked up from the
base classes of an object.
"""
for base in bases:
for class_ in base.__mro__:
yield class_
def is_final(name, mro):
"""
Checks if `name` is a `final` object in the given `mro`.
We need to check the mro because we need to directly go into the __dict__
of the classes. Because `final` objects are descriptor, we need to grab
them _BEFORE_ the `__call__` is invoked.
"""
return any(isinstance(getattr(c, '__dict__', {}).get(name), final)
for c in bases_mro(mro))
class FinalMeta(type):
"""A metaclass template for classes the want to prevent subclassess from
overriding a some methods or attributes.
"""
def __new__(mcls, name, bases, dict_):
for k, v in iteritems(dict_):
if is_final(k, bases):
raise _type_error
setattr_ = dict_.get('__setattr__')
if setattr_ is None:
# No `__setattr__` was explicitly defined, look up the super
# class's. `bases[0]` will have a `__setattr__` because
# `object` does so we don't need to worry about the mro.
setattr_ = bases[0].__setattr__
if not is_final('__setattr__', bases) \
and not isinstance(setattr_, final):
# implicitly make the `__setattr__` a `final` object so that
# users cannot just avoid the descriptor protocol.
dict_['__setattr__'] = final(setattr_)
return super(FinalMeta, mcls).__new__(mcls, name, bases, dict_)
def __setattr__(self, name, value):
"""This stops the `final` attributes from being reassigned on the
class object.
"""
if is_final(name, self.__mro__):
raise _type_error
super(FinalMeta, self).__setattr__(name, value)
class final(with_metaclass(ABCMeta)):
"""
An attribute that cannot be overridden.
This is like the final modifier in Java.
Example usage:
>>> from six import with_metaclass
>>> class C(with_metaclass(FinalMeta)):
... @final
... def f(self):
... return 'value'
...
This constructs a class with final method `f`. This cannot be overridden
on the class object or on any instance. You cannot override this by
subclassing `C`; attempting to do so will raise a `TypeError` at class
construction time.
"""
def __new__(cls, attr):
# Decide if this is a method wrapper or an attribute wrapper.
# We are going to cache the `callable` check by creating a
# method or attribute wrapper.
if hasattr(attr, '__get__'):
return object.__new__(finaldescriptor)
else:
return object.__new__(finalvalue)
def __init__(self, attr):
self._attr = attr
def __set__(self, instance, value):
"""
`final` objects cannot be reassigned. This is the most import concept
about `final`s.
Unlike a `property` object, this will raise a `TypeError` when you
attempt to reassign it.
"""
raise _type_error
@abstractmethod
def __get__(self, instance, owner):
raise NotImplementedError('__get__')
class finalvalue(final):
"""
A wrapper for a non-descriptor attribute.
"""
def __get__(self, instance, owner):
return self._attr
class finaldescriptor(final):
"""
A final wrapper around a descriptor.
"""
def __get__(self, instance, owner):
return self._attr.__get__(instance, owner)