setup.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  1. import os.path
  2. import pickle
  3. import sys
  4. from pkg_resources import (
  5. normalize_path,
  6. working_set,
  7. add_activation_listener,
  8. require,
  9. )
  10. from setuptools import setup
  11. from setuptools.command.build_py import build_py
  12. from setuptools.command.test import test as test_command
  13. class BuildPyCommand(build_py):
  14. """Custom build command to pre-compile Stan models."""
  15. def run(self):
  16. if not self.dry_run:
  17. self.build_stan_models()
  18. build_py.run(self)
  19. def build_stan_models(self):
  20. from pystan import StanModel
  21. target_dir = os.path.join(self.build_lib, 'fbprophet/stan_models')
  22. self.mkpath(target_dir)
  23. for model_type in ['linear', 'logistic']:
  24. with open('stan/prophet_{}_growth.stan'.format(model_type)) as f:
  25. model_code = f.read()
  26. sm = StanModel(model_code=model_code)
  27. with open(os.path.join(target_dir, '{}_growth.pkl'.format(model_type)), 'wb') as f:
  28. pickle.dump(sm, f, protocol=pickle.HIGHEST_PROTOCOL)
  29. class TestCommand(test_command):
  30. """We must run tests on the build directory, not source."""
  31. def with_project_on_sys_path(self, func):
  32. # Ensure metadata is up-to-date
  33. self.reinitialize_command('build_py', inplace=0)
  34. self.run_command('build_py')
  35. bpy_cmd = self.get_finalized_command("build_py")
  36. build_path = normalize_path(bpy_cmd.build_lib)
  37. # Build extensions
  38. self.reinitialize_command('egg_info', egg_base=build_path)
  39. self.run_command('egg_info')
  40. self.reinitialize_command('build_ext', inplace=0)
  41. self.run_command('build_ext')
  42. ei_cmd = self.get_finalized_command("egg_info")
  43. old_path = sys.path[:]
  44. old_modules = sys.modules.copy()
  45. try:
  46. sys.path.insert(0, normalize_path(ei_cmd.egg_base))
  47. working_set.__init__()
  48. add_activation_listener(lambda dist: dist.activate())
  49. require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version))
  50. func()
  51. finally:
  52. sys.path[:] = old_path
  53. sys.modules.clear()
  54. sys.modules.update(old_modules)
  55. working_set.__init__()
  56. setup(
  57. name='fbprophet',
  58. version='0.1.post1',
  59. description='Automatic Forecasting Procedure',
  60. url='https://facebookincubator.github.io/prophet/',
  61. author='Sean J. Taylor <sjt@fb.com>, Ben Letham <bletham@fb.com>',
  62. author_email='sjt@fb.com',
  63. license='BSD',
  64. packages=['fbprophet', 'fbprophet.tests'],
  65. setup_requires=[
  66. 'Cython>=0.22',
  67. 'pystan>=2.14',
  68. ],
  69. install_requires=[
  70. 'matplotlib',
  71. 'numpy',
  72. 'pandas>=0.16',
  73. 'pystan>=2.14',
  74. ],
  75. zip_safe=False,
  76. include_package_data=True,
  77. cmdclass={
  78. 'build_py': BuildPyCommand,
  79. 'test': TestCommand,
  80. },
  81. test_suite='fbprophet.tests.test_prophet',
  82. long_description="""
  83. Implements a procedure for forecasting time series data based on an additive model where non-linear trends are fit with yearly and weekly seasonality, plus holidays. It works best with daily periodicity data with at least one year of historical data. Prophet is robust to missing data, shifts in the trend, and large outliers.
  84. """
  85. )