__init__.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. # pylint: disable=C,R,W
  2. """Package's main module!"""
  3. import json
  4. import logging
  5. from logging.handlers import TimedRotatingFileHandler
  6. import os
  7. from flask import Flask, redirect
  8. from flask_appbuilder import AppBuilder, IndexView, SQLA
  9. from flask_appbuilder.baseviews import expose
  10. from flask_compress import Compress
  11. from flask_migrate import Migrate
  12. from flask_wtf.csrf import CSRFProtect
  13. from werkzeug.contrib.fixers import ProxyFix
  14. from superset import config, utils
  15. from superset.connectors.connector_registry import ConnectorRegistry
  16. from superset.security import SupersetSecurityManager
  17. APP_DIR = os.path.dirname(__file__)
  18. CONFIG_MODULE = os.environ.get('SUPERSET_CONFIG', 'superset.config')
  19. if not os.path.exists(config.DATA_DIR):
  20. os.makedirs(config.DATA_DIR)
  21. with open(APP_DIR + '/static/assets/backendSync.json', 'r') as f:
  22. frontend_config = json.load(f)
  23. app = Flask(__name__)
  24. app.config.from_object(CONFIG_MODULE)
  25. conf = app.config
  26. #################################################################
  27. # Handling manifest file logic at app start
  28. #################################################################
  29. MANIFEST_FILE = APP_DIR + '/static/assets/dist/manifest.json'
  30. manifest = {}
  31. def parse_manifest_json():
  32. global manifest
  33. try:
  34. with open(MANIFEST_FILE, 'r') as f:
  35. # the manifest inclues non-entry files
  36. # we only need entries in templates
  37. full_manifest = json.load(f)
  38. manifest = full_manifest.get('entrypoints', {})
  39. except Exception:
  40. pass
  41. def get_js_manifest_files(filename):
  42. if app.debug:
  43. parse_manifest_json()
  44. entry_files = manifest.get(filename, {})
  45. return entry_files.get('js', [])
  46. def get_css_manifest_files(filename):
  47. if app.debug:
  48. parse_manifest_json()
  49. entry_files = manifest.get(filename, {})
  50. return entry_files.get('css', [])
  51. def get_unloaded_chunks(files, loaded_chunks):
  52. filtered_files = [f for f in files if f not in loaded_chunks]
  53. for f in filtered_files:
  54. loaded_chunks.add(f)
  55. return filtered_files
  56. parse_manifest_json()
  57. @app.context_processor
  58. def get_manifest():
  59. return dict(
  60. loaded_chunks=set(),
  61. get_unloaded_chunks=get_unloaded_chunks,
  62. js_manifest=get_js_manifest_files,
  63. css_manifest=get_css_manifest_files,
  64. )
  65. #################################################################
  66. for bp in conf.get('BLUEPRINTS'):
  67. try:
  68. print("Registering blueprint: '{}'".format(bp.name))
  69. app.register_blueprint(bp)
  70. except Exception as e:
  71. print('blueprint registration failed')
  72. logging.exception(e)
  73. if conf.get('SILENCE_FAB'):
  74. logging.getLogger('flask_appbuilder').setLevel(logging.ERROR)
  75. if app.debug:
  76. app.logger.setLevel(logging.DEBUG)
  77. else:
  78. # In production mode, add log handler to sys.stderr.
  79. app.logger.addHandler(logging.StreamHandler())
  80. app.logger.setLevel(logging.INFO)
  81. logging.getLogger('pyhive.presto').setLevel(logging.INFO)
  82. db = SQLA(app)
  83. if conf.get('WTF_CSRF_ENABLED'):
  84. csrf = CSRFProtect(app)
  85. csrf_exempt_list = conf.get('WTF_CSRF_EXEMPT_LIST', [])
  86. for ex in csrf_exempt_list:
  87. csrf.exempt(ex)
  88. utils.pessimistic_connection_handling(db.engine)
  89. cache = utils.setup_cache(app, conf.get('CACHE_CONFIG'))
  90. tables_cache = utils.setup_cache(app, conf.get('TABLE_NAMES_CACHE_CONFIG'))
  91. migrate = Migrate(app, db, directory=APP_DIR + '/migrations')
  92. # Logging configuration
  93. logging.basicConfig(format=app.config.get('LOG_FORMAT'))
  94. logging.getLogger().setLevel(app.config.get('LOG_LEVEL'))
  95. if app.config.get('ENABLE_TIME_ROTATE'):
  96. logging.getLogger().setLevel(app.config.get('TIME_ROTATE_LOG_LEVEL'))
  97. handler = TimedRotatingFileHandler(
  98. app.config.get('FILENAME'),
  99. when=app.config.get('ROLLOVER'),
  100. interval=app.config.get('INTERVAL'),
  101. backupCount=app.config.get('BACKUP_COUNT'))
  102. logging.getLogger().addHandler(handler)
  103. if app.config.get('ENABLE_CORS'):
  104. from flask_cors import CORS
  105. CORS(app, **app.config.get('CORS_OPTIONS'))
  106. if app.config.get('ENABLE_PROXY_FIX'):
  107. app.wsgi_app = ProxyFix(app.wsgi_app)
  108. if app.config.get('ENABLE_CHUNK_ENCODING'):
  109. class ChunkedEncodingFix(object):
  110. def __init__(self, app):
  111. self.app = app
  112. def __call__(self, environ, start_response):
  113. # Setting wsgi.input_terminated tells werkzeug.wsgi to ignore
  114. # content-length and read the stream till the end.
  115. if environ.get('HTTP_TRANSFER_ENCODING', '').lower() == u'chunked':
  116. environ['wsgi.input_terminated'] = True
  117. return self.app(environ, start_response)
  118. app.wsgi_app = ChunkedEncodingFix(app.wsgi_app)
  119. if app.config.get('UPLOAD_FOLDER'):
  120. try:
  121. os.makedirs(app.config.get('UPLOAD_FOLDER'))
  122. except OSError:
  123. pass
  124. for middleware in app.config.get('ADDITIONAL_MIDDLEWARE'):
  125. app.wsgi_app = middleware(app.wsgi_app)
  126. class MyIndexView(IndexView):
  127. @expose('/')
  128. def index(self):
  129. return redirect('/superset/welcome')
  130. custom_sm = app.config.get('CUSTOM_SECURITY_MANAGER') or SupersetSecurityManager
  131. if not issubclass(custom_sm, SupersetSecurityManager):
  132. raise Exception(
  133. """Your CUSTOM_SECURITY_MANAGER must now extend SupersetSecurityManager,
  134. not FAB's security manager.
  135. See [4565] in UPDATING.md""")
  136. appbuilder = AppBuilder(
  137. app,
  138. db.session,
  139. base_template='superset/base.html',
  140. indexview=MyIndexView,
  141. security_manager_class=custom_sm,
  142. update_perms=utils.get_update_perms_flag(),
  143. )
  144. security_manager = appbuilder.sm
  145. results_backend = app.config.get('RESULTS_BACKEND')
  146. # Registering sources
  147. module_datasource_map = app.config.get('DEFAULT_MODULE_DS_MAP')
  148. module_datasource_map.update(app.config.get('ADDITIONAL_MODULE_DS_MAP'))
  149. ConnectorRegistry.register_sources(module_datasource_map)
  150. # Flask-Compress
  151. if conf.get('ENABLE_FLASK_COMPRESS'):
  152. Compress(app)
  153. # Hook that provides administrators a handle on the Flask APP
  154. # after initialization
  155. flask_app_mutator = app.config.get('FLASK_APP_MUTATOR')
  156. if flask_app_mutator:
  157. flask_app_mutator(app)
  158. from superset import views # noqa