Skip to content

Commit

Permalink
DEV: Adds type hinting stub for zipline.api
Browse files Browse the repository at this point in the history
as well as tooling and docs to generate this for each release

Also moved Cython files to package_data, so that we install them,
instead of just packaging them.
  • Loading branch information
richafrank committed May 19, 2016
1 parent 977e557 commit b9b4dc0
Show file tree
Hide file tree
Showing 5 changed files with 761 additions and 3 deletions.
2 changes: 0 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,5 @@ include LICENSE

include etc/requirements*.txt
recursive-include zipline/resources *.*
recursive-include zipline *.pyx
recursive-include zipline *.pxi
include versioneer.py
include zipline/_version.py
26 changes: 26 additions & 0 deletions docs/source/release-process.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,32 @@ update the underline of the title to match the title's width.
If you are renaming the release at this point, you'll need to git mv the file
and also update releases.rst to reference the renamed file.

Updating the Python stub files
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

PyCharm and other linters and type checkers can use `Python stub files
<https://www.python.org/dev/peps/pep-0484/#stub-files>`__ for type hinting. For
example, we generate stub files for the :mod:`~zipline.api` namespace, since that
namespace is populated at import time by decorators on TradingAlgorithm
methods. Those functions are therefore hidden from static analysis tools, but
we can generate static files to make them available. Under **Python 3**, run
the following to generate any stub files:

.. code-block:: bash
$ python etc/gen_type_stubs.py
.. note::

In order to make stub consumers aware of the classes referred to in the
stub, the stub file should import those classes. However, since
``... import *`` and ``... import ... as ...`` in a stub file will export
those imports, we import the names explicitly. For the stub for
``zipline.api``, this is done in a header string in the
``gen_type_stubs.py`` script mentioned above. If new classes are added as
parameters or return types of ``zipline.api`` functions, then new imports
should be added to that header.

Updating the ``__version__``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
42 changes: 42 additions & 0 deletions etc/gen_type_stubs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import inspect
from operator import attrgetter
from textwrap import dedent

from zipline import api, TradingAlgorithm


def main():
with open(api.__file__.rstrip('c') + 'i', 'w') as stub:
# Imports so that Asset et al can be resolved.
# "from MOD import *" will re-export the imports from the stub, so
# explicitly importing.
stub.write(dedent("""\
from zipline.assets import Asset, Equity, Future
from zipline.assets.futures import FutureChain
from zipline.finance.cancel_policy import CancelPolicy
from zipline.pipeline import Pipeline
from zipline.protocol import Order
from zipline.utils.events import EventRule
"""))

# Sort to generate consistent stub file:
for api_func in sorted(TradingAlgorithm.all_api_methods(),
key=attrgetter('__name__')):
sig = inspect._signature_bound_method(inspect.signature(api_func))

indent = ' ' * 4
stub.write(dedent('''\
def {func_name}{func_sig}:
"""'''.format(func_name=api_func.__name__,
func_sig=sig)))
stub.write(dedent('{indent}{func_doc}'.format(
func_doc=api_func.__doc__ or '\n', # handle None docstring
indent=indent,
)))
stub.write('{indent}"""\n\n'.format(indent=indent))


if __name__ == '__main__':
main()
6 changes: 5 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,9 +270,13 @@ def setup_requirements(requirements_path, module_names, strict_bounds,
},
author='Quantopian Inc.',
author_email='[email protected]',
packages=find_packages('.', include=['zipline', 'zipline.*']),
packages=find_packages(include=['zipline', 'zipline.*']),
ext_modules=ext_modules,
include_package_data=True,
package_data={root.replace(os.sep, '.'):
['*.pyi', '*.pyx', '*.pxi', '*.pxd']
for root, dirnames, filenames in os.walk('zipline')
if '__pycache__' not in root},
license='Apache 2.0',
classifiers=[
'Development Status :: 4 - Beta',
Expand Down
Loading

0 comments on commit b9b4dc0

Please sign in to comment.