ENH: fix the quality of life issues in the CLI

Fixes the issues presented in #1181 by @ssanderson around the new
command line interface.
This commit is contained in:
Joe Jevnik
2016-05-05 15:45:23 -04:00
parent 89542e33bd
commit 0b3a35891e
6 changed files with 45 additions and 18 deletions
+5
View File
@@ -260,6 +260,11 @@ setup(
version=versioneer.get_version(),
cmdclass=LazyBuildExtCommandClass(versioneer.get_cmdclass()),
description='A backtester for financial algorithms.',
entry_points={
'console_scripts': [
'zipline = zipline.__main__:main',
],
},
author='Quantopian Inc.',
author_email='opensource@quantopian.com',
packages=find_packages('.', include=['zipline', 'zipline.*']),
+30 -8
View File
@@ -5,8 +5,9 @@ import click
import logbook
import pandas as pd
from zipline.data import bundles
from zipline.data import bundles as bundles_module
from zipline.utils.cli import Date, Timestamp
import zipline.utils.paths as pth
from zipline.utils.run_algo import _run, load_extensions
try:
@@ -36,7 +37,7 @@ except NameError:
default=True,
help="Don't load the default zipline extension.py file in $ZIPLINE_HOME.",
)
def cli(extension, strict_extensions, default_extension):
def main(extension, strict_extensions, default_extension):
"""Top level zipline entry point.
"""
# install a logbook handler before performing any other operations
@@ -97,7 +98,7 @@ def ipython_only(option):
return d
@cli.command()
@main.command()
@click.option(
'-f',
'--algofile',
@@ -273,7 +274,7 @@ def zipline_magic(line, cell=None):
raise ValueError('main returned non-zero status code: %d' % e.code)
@cli.command()
@main.command()
@click.option(
'-b',
'--bundle',
@@ -291,7 +292,7 @@ def zipline_magic(line, cell=None):
def ingest(bundle, show_progress):
"""Ingest the data for the given bundle.
"""
bundles.ingest(
bundles_module.ingest(
bundle,
os.environ,
pd.Timestamp.utcnow(),
@@ -299,7 +300,7 @@ def ingest(bundle, show_progress):
)
@cli.command()
@main.command()
@click.option(
'-b',
'--bundle',
@@ -333,7 +334,7 @@ def ingest(bundle, show_progress):
def clean(bundle, before, after, keep_last):
"""Clean up data downloaded with the ingest command.
"""
bundles.clean(
bundles_module.clean(
bundle,
before,
after,
@@ -341,5 +342,26 @@ def clean(bundle, before, after, keep_last):
)
@main.command()
def bundles():
"""List all of the available data bundles.
"""
for bundle in sorted(bundles_module.bundles.keys()):
ingestions = sorted(
(str(pd.Timestamp(int(ing)))
for ing in os.listdir(pth.data_path([bundle]))
if not pth.hidden(ing)),
reverse=True,
)
print(
'\n'.join(
'%s %s' % (bundle, line)
for line in (
ingestions if ingestions else ('<no ingestions>',)
)
),
)
if __name__ == '__main__':
cli()
main()
+1 -1
View File
@@ -101,7 +101,7 @@ class AssetFinder(object):
PERSISTENT_TOKEN = "<AssetFinder>"
def __init__(self, engine):
if isinstance(engine, str):
if isinstance(engine, string_types):
engine = sa.create_engine('sqlite:///' + engine)
self.engine = engine
+2
View File
@@ -319,6 +319,8 @@ def quantopian_quandl_bundle(environ,
cache,
show_progress,
output_dir):
if show_progress:
print('Downloading quandl data, can take about 1 minute')
# use closing for py2 compat
with closing(urlopen(QUANTOPIAN_QUANDL_URL)) as f, \
tarfile.open('r', fileobj=BytesIO(f.read())) as tar:
+6 -8
View File
@@ -194,7 +194,7 @@ class dataframe_cache(MutableMapping):
self._protocol = int(s[1]) if len(s) == 2 else None
self.serialize = self._serialize_pickle
self.deserialize = self._deserialize_pickle
self.deserialize = pickle.load
ensure_directory(self.path)
@@ -202,10 +202,6 @@ class dataframe_cache(MutableMapping):
with open(path, 'wb') as f:
pickle.dump(df, f, protocol=self._protocol)
def _deserialize_pickle(self, path):
with open(path, 'rb') as f:
return pickle.load(f)
def _keypath(self, key):
return os.path.join(self.path, key)
@@ -226,9 +222,11 @@ class dataframe_cache(MutableMapping):
with self.lock:
try:
return self.deserialize(self._keypath(key))
except UnboundLocalError:
# This is how pandas fails if the file doesn't exist! #pandas
with open(self._keypath(key), 'rb') as f:
return self.deserialize(f)
except IOError as e:
if e.errno != errno.ENOENT:
raise
raise KeyError(key)
def __setitem__(self, key, value):
+1 -1
View File
@@ -145,7 +145,7 @@ def _run(handle_data,
'before_trading_start': before_trading_start,
'analyze': analyze,
} if algotext is None else {
'algo_filename': algofile,
'algo_filename': algofile.name,
'script': algotext,
}
).run(