content: # Copyright Contributors to the Amundsen project.
  # SPDX-License-Identifier: Apache-2.0
  
  import ast
  import importlib
  import logging
  import logging.config
  import os
  import sys
  from typing import Any, Dict  # noqa: F401
  
  from flasgger import Swagger
  from flask import Blueprint, Flask
  from flask_cors import CORS
  from flask_restful import Api
  from werkzeug.utils import import_string
  
  from metadata_service.api.badge import BadgeAPI
  from metadata_service.api.column import (ColumnBadgeAPI, ColumnDescriptionAPI,
                                           ColumnLineageAPI)
  from metadata_service.api.dashboard import (DashboardBadgeAPI,
                                              DashboardDescriptionAPI,
                                              DashboardDetailAPI,
                                              DashboardTagAPI)
  from metadata_service.api.feature import (FeatureBadgeAPI,
                                            FeatureDescriptionAPI,
                                            FeatureDetailAPI,
                                            FeatureGenerationCodeAPI,
                                            FeatureLineageAPI, FeatureOwnerAPI,
                                            FeatureSampleAPI, FeatureStatsAPI,
                                            FeatureTagAPI)
  from metadata_service.api.healthcheck import HealthcheckAPI
  from metadata_service.api.popular_resources import PopularResourcesAPI
  from metadata_service.api.popular_tables import PopularTablesAPI
  from metadata_service.api.system import Neo4jDetailAPI, StatisticsMetricsAPI
  from metadata_service.api.table import (TableBadgeAPI, TableDashboardAPI,
                                          TableDescriptionAPI, TableDetailAPI,
                                          TableLineageAPI, TableOwnerAPI,
                                          TableTagAPI)
  from metadata_service.api.tag import TagAPI
  from metadata_service.api.type_metadata import (TypeMetadataBadgeAPI,
                                                  TypeMetadataDescriptionAPI)
  from metadata_service.api.user import (UserDetailAPI, UserFollowAPI,
                                         UserFollowsAPI, UserOwnAPI, UserOwnsAPI,
                                         UserReadsAPI)
  from metadata_service.deprecations import process_deprecations
  
  # For customized flask use below arguments to override.
  FLASK_APP_MODULE_NAME = os.getenv('FLASK_APP_MODULE_NAME')
  FLASK_APP_CLASS_NAME = os.getenv('FLASK_APP_CLASS_NAME')
  FLASK_APP_KWARGS_DICT_STR = os.getenv('FLASK_APP_KWARGS_DICT')
  ROOT_DIR = os.path.dirname(os.path.abspath(__file__))
  
  # Environment Variable to enable cors
  CORS_ENABLED = os.environ.get('CORS_ENABLED', False)
  
  
  def create_app(*, config_module_class: str) -> Flask:
      """
      Creates app in function so that flask with flask extensions can be
      initialized with specific config. Here it defines the route of APIs
      so that it can be seen in one place where implementation is separated.
  
      Config is being fetched via module.class name where module.class name
      can be passed through environment variable.
      This is to make config fetched through runtime PYTHON_PATH so that
      Config class can be easily injected.
      More on: http://flask.pocoo.org/docs/1.0/config/
  
      :param config_module_class: name of the config (TODO: Implement config.py)
      :return: Flask
      """
      if FLASK_APP_MODULE_NAME and FLASK_APP_CLASS_NAME:
          print('Using requested Flask module {module_name} and class {class_name}'
                .format(module_name=FLASK_APP_MODULE_NAME, class_name=FLASK_APP_CLASS_NAME), file=sys.stderr)
          class_obj = getattr(importlib.import_module(FLASK_APP_MODULE_NAME), FLASK_APP_CLASS_NAME)
  
          flask_kwargs_dict = {}  # type: Dict[str, Any]
          if FLASK_APP_KWARGS_DICT_STR:
              print('Using kwargs {kwargs} to instantiate Flask'.format(kwargs=FLASK_APP_KWARGS_DICT_STR),
                    file=sys.stderr)
              flask_kwargs_dict = ast.literal_eval(FLASK_APP_KWARGS_DICT_STR)
  
          app = class_obj(__name__, **flask_kwargs_dict)
  
      else:
          app = Flask(__name__)
  
      if CORS_ENABLED:
          CORS(app)
      config_module_class = \
          os.getenv('METADATA_SVC_CONFIG_MODULE_CLASS') or config_module_class
      app.config.from_object(config_module_class)
  
      if app.config.get('LOG_CONFIG_FILE'):
          logging.config.fileConfig(app.config.get('LOG_CONFIG_FILE'), disable_existing_loggers=False)
      else:
          logging.basicConfig(format=app.config.get('LOG_FORMAT'), datefmt=app.config.get('LOG_DATE_FORMAT'))
          logging.getLogger().setLevel(app.config.get('LOG_LEVEL'))
      logging.info('Created app with config name {}'.format(config_module_class))
      logging.info('Using backend {}'.format(app.config.get('PROXY_CLIENT')))
  
      # Initialize custom extensions and routes
      init_custom_ext_routes = app.config.get('INIT_CUSTOM_EXT_AND_ROUTES')
      if init_custom_ext_routes:
          init_custom_ext_routes(app)
  
      api_bp = Blueprint('api', __name__)
      api = Api(api_bp)
  
      api.add_resource(HealthcheckAPI, '/healthcheck')
  
      # `PopularTablesAPI` is deprecated, and will be removed in version 4.
      api.add_resource(PopularTablesAPI,
                       '/popular_tables/',
                       '/popular_tables/<path:user_id>')
      api.add_resource(PopularResourcesAPI,
                       '/popular_resources/',
                       '/popular_resources/<path:user_id>')
      api.add_resource(TableDetailAPI, '/table/<path:table_uri>')
      api.add_resource(TableDescriptionAPI,
                       '/table/<path:id>/description')
      api.add_resource(TableTagAPI,
                       '/table/<path:id>/tag/<tag>')
      api.add_resource(TableBadgeAPI,
                       '/table/<path:id>/badge/<badge>')
      api.add_resource(TableLineageAPI,
                       '/table/<path:id>/lineage')
      api.add_resource(TableOwnerAPI,
                       '/table/<path:table_uri>/owner/<owner>')
      api.add_resource(TableDashboardAPI,
                       '/table/<path:id>/dashboard/')
      api.add_resource(ColumnDescriptionAPI,
                       '/table/<path:table_uri>/column/<column_name>/description')
      api.add_resource(ColumnBadgeAPI,
                       '/table/<path:table_uri>/column/<column_name>/badge/<badge>')
      api.add_resource(ColumnLineageAPI,
                       '/table/<path:table_uri>/column/<column_name>/lineage')
      api.add_resource(TypeMetadataDescriptionAPI,
                       '/type_metadata/<path:type_metadata_key>/description')
      api.add_resource(TypeMetadataBadgeAPI,
                       '/type_metadata/<path:type_metadata_key>/badge/<badge>')
      api.add_resource(Neo4jDetailAPI,
                       '/latest_updated_ts')
      api.add_resource(StatisticsMetricsAPI,
                       '/system/statistics')
      api.add_resource(TagAPI,
                       '/tags/')
      api.add_resource(BadgeAPI,
                       '/badges/')
      api.add_resource(UserDetailAPI,
                       '/user',
                       '/user/<path:id>')
      api.add_resource(UserFollowsAPI,
                       '/user/<path:user_id>/follow/')
      api.add_resource(UserFollowAPI,
                       '/user/<path:user_id>/follow/<resource_type>/<path:resource_id>')
      api.add_resource(UserOwnsAPI,
                       '/user/<path:user_id>/own/')
      api.add_resource(UserOwnAPI,
                       '/user/<path:user_id>/own/<resource_type>/<path:table_uri>')
      api.add_resource(UserReadsAPI,
                       '/user/<path:user_id>/read/')
      api.add_resource(DashboardDetailAPI,
                       '/dashboard/<path:id>')
      api.add_resource(DashboardDescriptionAPI,
                       '/dashboard/<path:id>/description')
      api.add_resource(DashboardTagAPI,
                       '/dashboard/<path:id>/tag/<tag>')
      api.add_resource(DashboardBadgeAPI,
                       '/dashboard/<path:id>/badge/<badge>')
      api.add_resource(FeatureDetailAPI, '/feature/<path:feature_uri>')
      api.add_resource(FeatureDescriptionAPI,
                       '/feature/<path:id>/description')
      api.add_resource(FeatureTagAPI,
                       '/feature/<path:id>/tag/<tag>')
      api.add_resource(FeatureBadgeAPI,
                       '/feature/<path:id>/badge/<badge>')
      api.add_resource(FeatureLineageAPI,
                       '/feature/<path:id>/lineage')
      api.add_resource(FeatureOwnerAPI,
                       '/feature/<path:feature_uri>/owner/<owner>')
      api.add_resource(FeatureStatsAPI,
                       '/feature/<path:id>/stats')
      api.add_resource(FeatureSampleAPI,
                       '/feature/<path:id>/sample_data')
      api.add_resource(FeatureGenerationCodeAPI,
                       '/feature/<path:feature_uri>/generation_code')
      app.register_blueprint(api_bp)
  
      # cli registration
      proxy_cli = app.config.get('PROXY_CLI')
      if proxy_cli:
          app.cli.add_command(import_string(proxy_cli))
          logging.info('Using cli {}'.format(proxy_cli))
  
      if app.config.get('SWAGGER_ENABLED'):
          Swagger(app, template_file=os.path.join(ROOT_DIR, app.config.get('SWAGGER_TEMPLATE_PATH')), parse=True)
  
      # handles the deprecation warnings
      # and process any config/environment variables accordingly
      process_deprecations(app)
  
      return app
  