diff --git a/.gitignore b/.gitignore index 6b24f107..143aed10 100644 --- a/.gitignore +++ b/.gitignore @@ -338,3 +338,6 @@ ASALocalRun/ # MFractors (Xamarin productivity tool) working folder .mfractor/ .env + +# Python env +env/ diff --git a/examples/Python/python-django-webapp-sample/hello_azure/views.py b/examples/Python/python-django-webapp-sample/hello_azure/views.py index 51c2b36a..adcdbb65 100644 --- a/examples/Python/python-django-webapp-sample/hello_azure/views.py +++ b/examples/Python/python-django-webapp-sample/hello_azure/views.py @@ -1,15 +1,15 @@ from django.shortcuts import render from django.conf import settings -def index(request): + +async def index(request): # Refresh the configuration from App Configuration service. - settings.AZURE_APPCONFIGURATION.refresh() - # Update Django settings with the app configuration key-values - settings.CONFIG.update(settings.AZURE_APPCONFIGURATION) + settings.AZURE_APP_CONFIG.refresh() + context = { - "message": settings.CONFIG.get('message'), - "key": settings.CONFIG.get('secret_key'), - "color": settings.CONFIG.get('color'), - "font_size": settings.CONFIG.get('font_size') - } - return render(request, 'hello_azure/index.html', context) + "message": settings.CONFIG.get("message"), + "key": settings.CONFIG.get("secret_key"), + "color": settings.CONFIG.get("color"), + "font_size": settings.CONFIG.get("font_size"), + } + return render(request, "hello_azure/index.html", context) diff --git a/examples/Python/python-django-webapp-sample/quickstartproject/settings.py b/examples/Python/python-django-webapp-sample/quickstartproject/settings.py index 9e79b05b..e3248256 100644 --- a/examples/Python/python-django-webapp-sample/quickstartproject/settings.py +++ b/examples/Python/python-django-webapp-sample/quickstartproject/settings.py @@ -11,15 +11,16 @@ """ import os -from pathlib import Path import configparser -from azure.appconfiguration.provider import load, SettingSelector, SentinelKey +from pathlib import Path +from azure.appconfiguration.provider import SettingSelector, WatchKey +from azure.appconfiguration.provider.aio import load from azure.identity import DefaultAzureCredential c_parser = configparser.ConfigParser() -c_parser.read('static/config.ini') +c_parser.read("static/config.ini") -CONFIG = c_parser['DEFAULT'] +CONFIG = c_parser["DEFAULT"] ENDPOINT = os.environ.get("AZURE_APPCONFIG_ENDPOINT") @@ -30,17 +31,28 @@ # Select only key-values that start with 'testapp_settings_' and trim the prefix selects = SettingSelector(key_filter="testapp_settings_*") selects_secret = SettingSelector(key_filter="secret_key") -AZURE_APPCONFIGURATION = load(endpoint=ENDPOINT, - keyvault_credential=credential, - credential=credential, - selects=[selects, selects_secret], - trim_prefixes=["testapp_settings_"], - refresh_on=[SentinelKey("sentinel")] - ) + + +def callback(): + global AZURE_APP_CONFIG + # Update Django settings with the app configuration key-values + CONFIG.update(AZURE_APP_CONFIG) + + +AZURE_APP_CONFIG = load( + endpoint=ENDPOINT, + selects=[selects, selects_secret], + credential=credential, + keyvault_credential=credential, + trim_prefixes=["testapp_settings_"], + refresh_on=[WatchKey("sentinel")], + on_refresh_success=callback, +) + # Updates the config object with the app configuration key-values and resolved key vault reference values. # This will override any values in the config object with the same key. -CONFIG.update(AZURE_APPCONFIGURATION) +CONFIG.update(AZURE_APP_CONFIG) # Build paths inside the project like this: BASE_DIR / 'subdir'. BASE_DIR = Path(__file__).resolve().parent.parent @@ -50,7 +62,7 @@ # SECURITY WARNING: keep the secret key used in production secret! # This is a key vault reference. The corresponding secret in key vault is returned. -SECRET_KEY = CONFIG.get('secret_key') +SECRET_KEY = CONFIG.get("secret_key") # SECURITY WARNING: don't run with debug turned on in production! DEBUG = True @@ -61,53 +73,53 @@ # Application definition INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'hello_azure' + "django.contrib.admin", + "django.contrib.auth", + "django.contrib.contenttypes", + "django.contrib.sessions", + "django.contrib.messages", + "django.contrib.staticfiles", + "hello_azure", ] MIDDLEWARE = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', + "django.middleware.security.SecurityMiddleware", + "django.contrib.sessions.middleware.SessionMiddleware", + "django.middleware.common.CommonMiddleware", + "django.middleware.csrf.CsrfViewMiddleware", + "django.contrib.auth.middleware.AuthenticationMiddleware", + "django.contrib.messages.middleware.MessageMiddleware", + "django.middleware.clickjacking.XFrameOptionsMiddleware", ] -ROOT_URLCONF = 'quickstartproject.urls' +ROOT_URLCONF = "quickstartproject.urls" TEMPLATES = [ { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', + "BACKEND": "django.template.backends.django.DjangoTemplates", + "DIRS": [], + "APP_DIRS": True, + "OPTIONS": { + "context_processors": [ + "django.template.context_processors.debug", + "django.template.context_processors.request", + "django.contrib.auth.context_processors.auth", + "django.contrib.messages.context_processors.messages", ], }, }, ] -WSGI_APPLICATION = 'quickstartproject.wsgi.application' +WSGI_APPLICATION = "quickstartproject.wsgi.application" # Database # https://docs.djangoproject.com/en/4.0/ref/settings/#databases DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': BASE_DIR / 'db.sqlite3', + "default": { + "ENGINE": "django.db.backends.sqlite3", + "NAME": BASE_DIR / "db.sqlite3", } } @@ -117,16 +129,16 @@ AUTH_PASSWORD_VALIDATORS = [ { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + "NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + "NAME": "django.contrib.auth.password_validation.MinimumLengthValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + "NAME": "django.contrib.auth.password_validation.CommonPasswordValidator", }, { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + "NAME": "django.contrib.auth.password_validation.NumericPasswordValidator", }, ] @@ -134,9 +146,9 @@ # Internationalization # https://docs.djangoproject.com/en/4.0/topics/i18n/ -LANGUAGE_CODE = 'en-us' +LANGUAGE_CODE = "en-us" -TIME_ZONE = 'UTC' +TIME_ZONE = "UTC" USE_I18N = True @@ -146,10 +158,10 @@ # Static files (CSS, JavaScript, Images) # https://docs.djangoproject.com/en/4.0/howto/static-files/ -STATICFILES_DIRS = (str(BASE_DIR.joinpath('static')),) -STATIC_URL = 'static/' +STATICFILES_DIRS = (str(BASE_DIR.joinpath("static")),) +STATIC_URL = "static/" # Default primary key field type # https://docs.djangoproject.com/en/4.0/ref/settings/#default-auto-field -DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' +DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" diff --git a/examples/Python/python-django-webapp-sample/requirements.txt b/examples/Python/python-django-webapp-sample/requirements.txt index a69d1379..bad56bb5 100644 --- a/examples/Python/python-django-webapp-sample/requirements.txt +++ b/examples/Python/python-django-webapp-sample/requirements.txt @@ -1,4 +1,4 @@ Django==4.1.13 whitenoise==6.4.0 -azure-appconfiguration-provider==1.1.0b1 +azure-appconfiguration-provider==1.1.0b3 azure-identity==1.12.0 diff --git a/examples/Python/python-flask-webapp-sample/app.py b/examples/Python/python-flask-webapp-sample/app.py index e12643e0..b74e6437 100644 --- a/examples/Python/python-flask-webapp-sample/app.py +++ b/examples/Python/python-flask-webapp-sample/app.py @@ -1,46 +1,49 @@ import os from flask import Flask, render_template -from azure.appconfiguration.provider import load, SettingSelector, SentinelKey +from azure.appconfiguration.provider import load, SettingSelector, WatchKey from azure.identity import DefaultAzureCredential app = Flask(__name__) - -ENDPOINT = os.environ.get("AZURE_APPCONFIG_ENDPOINT") - -# Set up credentials and settings used in resolving key vault references. +ENDPOINT = os.environ.get("AZURE_APPCONFIG_ENDPOINT") credential = DefaultAzureCredential() - -# Load app configuration key-values and resolved key vault reference values. -# Select only key-values that start with 'testapp_settings_' and trim the prefix selects = SettingSelector(key_filter="testapp_settings_*") selects_secret = SettingSelector(key_filter="secret_key") -azure_app_config = load(endpoint=ENDPOINT, - keyvault_credential=credential, - credential=credential, - selects=[selects, selects_secret], - trim_prefixes=["testapp_settings_"], - refresh_on=[SentinelKey("sentinel")], - ) - -# App Configuration provider implements the Mapping Type which is compatible with the existing Flask config. -# Update Flask config mapping with loaded values in the App Configuration provider. + + +def callback(): + app.config.update(azure_app_config) + + +global azure_app_config +azure_app_config = load( + endpoint=ENDPOINT, + selects=[selects, selects_secret], + credential=credential, + keyvault_credential=credential, + trim_prefixes=["testapp_settings_"], + refresh_on=[WatchKey("sentinel")], + on_refresh_success=callback, +) app.config.update(azure_app_config) -@app.route('/') + +@app.route("/") def index(): - # Refresh the configuration from App Configuration service. - azure_app_config.refresh() - # Update Flask config mapping with loaded values in the App Configuration provider. - app.config.update(azure_app_config) - print('Request for index page received') - context = {} - context['message'] = app.config.get('message') - context['font_size'] = app.config.get('font_size') - context['color'] = app.config.get('color') - context['key'] = app.config.get('secret_key') # This is a key vault reference. The corresponding secret in key vault is returned. - return render_template('index.html', **context) - - -if __name__ == '__main__': - app.run() + global azure_app_config + # Refresh the configuration from App Configuration service. + azure_app_config.refresh() + + print("Request for index page received") + context = {} + context["message"] = app.config.get("message") + context["font_size"] = app.config.get("font_size") + context["color"] = app.config.get("color") + context["key"] = app.config.get( + "secret_key" + ) # This is a key vault reference. The corresponding secret in key vault is returned. + return render_template("index.html", **context) + + +if __name__ == "__main__": + app.run() diff --git a/examples/Python/python-flask-webapp-sample/requirements.txt b/examples/Python/python-flask-webapp-sample/requirements.txt index 9460bc98..7d770540 100644 --- a/examples/Python/python-flask-webapp-sample/requirements.txt +++ b/examples/Python/python-flask-webapp-sample/requirements.txt @@ -1,3 +1,3 @@ Flask==2.3.2 azure-identity==1.12.0 -azure-appconfiguration-provider==1.1.0b2 +azure-appconfiguration-provider==1.1.0b3