From eba27869ffc81b2eaffd2565d0dca0787cc3a992 Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 18:04:06 -0700 Subject: [PATCH 01/10] Add environ.py and some basic tests. Lets see if they run on travis. --- .travis.yml | 4 +- gaek/environ.py | 181 ++++++++++++++++++++++++++++++++++++++++++ tests/test_environ.py | 56 +++++++++++++ 3 files changed, 239 insertions(+), 2 deletions(-) create mode 100644 gaek/environ.py create mode 100755 tests/test_environ.py diff --git a/.travis.yml b/.travis.yml index fbbe4a5..d6b9da8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,8 @@ install: # environment dependencies before_script: - - curl -O https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.23.zip - - unzip -q google_appengine_1.9.23.zip + - curl -O https://storage.googleapis.com/appengine-sdks/featured/google_appengine_1.9.27.zip + - unzip -q google_appengine_1.9.27.zip - ln -s google_appengine/google google # command to run tests diff --git a/gaek/environ.py b/gaek/environ.py new file mode 100644 index 0000000..1f04e0a --- /dev/null +++ b/gaek/environ.py @@ -0,0 +1,181 @@ +# -*- coding: utf-8 -*- +""" +Environment discovery and helper functions for Google App Engine. +Some methods from the following modules have been made available for convenience: + +* [`google.appengine.api.app_identity`](https://cloud.google.com/appengine/docs/python/appidentity/) +* [`google.appengine.api.modules`](https://cloud.google.com/appengine/docs/python/modules/) +* [`google.appengine.api.namespace_manager`](https://cloud.google.com/appengine/docs/python/multitenancy/) + +Example: + + import environ + + # Only send emails in production. + if environ.is_production(): + mail.send(*args, **kwargs) + +""" + +__author__ = 'Eric Higgins' +__copyright__ = 'Copyright 2015, Eric Higgins' +__version__ = '0.0.1' +__email__ = 'erichiggins@gmail.com' + + +import os + +from google.appengine.api import app_identity +from google.appengine.api import modules +from google.appengine.api import namespace_manager + + +__all__ = ( + # App Identity functions. + 'get_application_id', + 'get_default_version_hostname', + 'get_service_account_name', + # Module functions. + 'get_current_instance_id', + 'get_current_module_name', + 'get_current_version_name', + 'get_default_version', + 'get_hostname', + 'get_modules', + 'get_versions', + # Namespace functions. + 'get_namespace', + 'google_apps_namespace', + # Helper functions. + 'get_dot_target_name', + 'get_environ_dict', + 'is_host_google', + 'is_development', + 'is_staging', + 'is_production', + 'is_default_version', +) + + +_UNDEFINED = '_UNDEFINED_' + + +# App Identity functions. +get_application_id = app_identity.get_application_id +get_default_version_hostname = app_identity.get_default_version_hostname +get_service_account_name = app_identity.get_service_account_name + + +# Module functions. +get_current_instance_id = modules.get_current_instance_id +get_current_module_name = modules.get_current_module_name +get_current_version_name = modules.get_current_version_name +get_default_version = modules.get_default_version +get_hostname = modules.get_hostname +get_modules = modules.get_modules +get_versions = modules.get_versions + + +# Namespace functions. +get_namespace = namespace_manager.get_namespace +google_apps_namespace = namespace_manager.google_apps_namespace + + +# Helper functions. + + +def is_host_google(): + """True if the app is being hosted from Google App Engine servers.""" + return os.environ.get('SERVER_SOFTWARE', '').startswith('Google') or get_hostname().endswith('.appspot.com') + + +def is_default_version(version=None): + """True if the current or specified app version is the default.""" + version = version or get_current_version_name() + return get_current_version_name() == get_default_version() + + +def is_development(): + """True if the dev_appserver is running (localhost or local development server).""" + return os.environ.get('SERVER_SOFTWARE', '').startswith('Development') + + +def is_staging(version=None): + """True if the app is hosted by Google (appspot.com) but the version is not the default.""" + return is_host_google() and not is_default_version(version) + + +def is_production(version=None): + """True if the app is being hosted by Google and the default version.""" + return is_host_google() and is_default_version(version) + + +def get_dot_target_name(version=None, module=None): + """Returns the current version/module in -dot- notation which is used by `target:` parameters.""" + version = version or get_current_version_name() + module = module or get_current_module_name() + return '-dot-'.join((version, module)) + + +def _get_os_environ_dict(keys): + """Return a dictionary of key/values from os.environ.""" + return {k: os.environ.get(k, _UNDEFINED) for k in keys} + + +def _get_app_identity_dict(keys): + """Return a dictionary of key/values from the app_identity module functions.""" + return {k: getattr(app_identity, k)() for k in keys} + + +def _get_modules_dict(keys): + """Return a dictionary of key/values from the modules module functions.""" + return {k: getattr(modules, k)() for k in keys} + + +def _get_namespace_manager_dict(keys): + """Return a dictionary of key/values from the namespace_manager module functions.""" + return {k: getattr(namespace_manager, k)() for k in keys} + + +def get_environ_dict(): + """Return a dictionary of all environment keys/values.""" + return { + 'os.environ': _get_os_environ_dict(( + 'AUTH_DOMAIN', + 'CURRENT_CONFIGURATION_VERSION', + 'CURRENT_MODULE_ID', + 'CURRENT_VERSION_ID', + 'DEFAULT_VERSION_HOSTNAME', + 'FEDERATED_IDENTITY', + 'FEDERATED_PROVIDER', + 'GAE_LOCAL_VM_RUNTIME', + 'HTTP_HOST', + 'HTTP_PROXY', + 'HTTP_X_APPENGINE_HTTPS', + 'HTTP_X_APPENGINE_QUEUENAME', + 'HTTP_X_ORIGINAL_HOST', + 'HTTP_X_ORIGINAL_SCHEME', + 'SERVER_NAME', + 'SERVER_PORT', + 'SERVER_SOFTWARE', + 'USER_IS_ADMIN', + )), + 'app_identity': _get_app_identity_dict(( + 'get_service_account_name', + 'get_application_id', + 'get_default_version_hostname', + )), + 'modules': _get_modules_dict(( + 'get_current_module_name', + 'get_current_version_name', + 'get_current_instance_id', + 'get_modules', + 'get_versions', + 'get_default_version', + 'get_hostname', + )), + 'namespace_manager': _get_namespace_manager_dict(( + 'get_namespace', + 'google_apps_namespace', + )), + } diff --git a/tests/test_environ.py b/tests/test_environ.py new file mode 100755 index 0000000..02e9dee --- /dev/null +++ b/tests/test_environ.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +test_environ +---------------------------------- + +Tests for `environ` module. +""" + +import os +import unittest + +from google.appengine.api import app_identity +from google.appengine.api import modules +from google.appengine.api import namespace_manager +from google.appengine.ext import testbed + +from gaek import environ + + +class TestEnviron(unittest.TestCase): + + def setUp(self): + # Setups app engine test bed. + # http://code.google.com/appengine/docs/python/tools/localunittesting.html + self.testbed = testbed.Testbed() + self.testbed.activate() + # Declare which service stubs you want to use. + self.testbed.init_app_identity_stub() + self.testbed.init_modules_stub() + + def tearDown(self): + self.testbed.deactivate() + + def test_app_identity_functions(self): + assert app_identity.get_application_id == environ.get_application_id + assert app_identity.get_default_version_hostname == environ.get_default_version_hostname + assert app_identity.get_service_account_name == environ.get_service_account_name + + def test_modules_functions(self): + assert namespace_manager.get_current_instance_id == environ.get_current_instance_id + assert namespace_manager.get_current_module_name == environ.get_current_module_name + assert namespace_manager.get_current_version_name == environ.get_current_version_name + assert namespace_manager.get_default_version == environ.get_default_version + assert namespace_manager.get_hostname == environ.get_hostname + assert namespace_manager.get_modules == environ.get_modules + assert namespace_manager.get_versions == environ.get_versions + + def test_namespace_functions(self): + assert namespace_manager.get_namespace == environ.get_namespace + assert namespace_manager.google_apps_namespace == environ.google_apps_namespace + + +if __name__ == '__main__': + unittest.main() From 11256f1abde60bcf90240a6d70e946b4b456720b Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 18:07:13 -0700 Subject: [PATCH 02/10] Fix typo in test -- modules instead of namespace_manager. --- tests/test_environ.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_environ.py b/tests/test_environ.py index 02e9dee..cf963a2 100755 --- a/tests/test_environ.py +++ b/tests/test_environ.py @@ -39,13 +39,13 @@ def test_app_identity_functions(self): assert app_identity.get_service_account_name == environ.get_service_account_name def test_modules_functions(self): - assert namespace_manager.get_current_instance_id == environ.get_current_instance_id - assert namespace_manager.get_current_module_name == environ.get_current_module_name - assert namespace_manager.get_current_version_name == environ.get_current_version_name - assert namespace_manager.get_default_version == environ.get_default_version - assert namespace_manager.get_hostname == environ.get_hostname - assert namespace_manager.get_modules == environ.get_modules - assert namespace_manager.get_versions == environ.get_versions + assert modules.get_current_instance_id == environ.get_current_instance_id + assert modules.get_current_module_name == environ.get_current_module_name + assert modules.get_current_version_name == environ.get_current_version_name + assert modules.get_default_version == environ.get_default_version + assert modules.get_hostname == environ.get_hostname + assert modules.get_modules == environ.get_modules + assert modules.get_versions == environ.get_versions def test_namespace_functions(self): assert namespace_manager.get_namespace == environ.get_namespace From b358df6e7c4e05a84ed03edc80c598c9853438ab Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 18:32:29 -0700 Subject: [PATCH 03/10] Update the README. --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a7ada69..aa5aeb8 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,7 @@ GAEK: Google App Engine Kit =============================== -.. image:: https://img.shields.io/travis/erichiggins/gaek.svg - :target: https://travis-ci.org/erichiggins/gaek - -.. image:: https://img.shields.io/pypi/v/gaek.svg - :target: https://pypi.python.org/pypi/gaek +[![Build Status](https://travis-ci.org/erichiggins/gaek.svg)](https://travis-ci.org/erichiggins/gaek) A collection of useful tools for Python apps running on Google App Engine. @@ -34,3 +30,15 @@ Feature parity with the Python `json` module functions. `ndb_json.dump` `ndb_json.loads` + + +Environment module +------------------ + +Usage: + + from gaek import environ + + +API: + From 49fc41f33364dfabdddf47a187e082117fe1fae1 Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 19:44:29 -0700 Subject: [PATCH 04/10] Add GAE files to gitignore. --- .gitignore | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitignore b/.gitignore index 82ba1ba..5f62e89 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,9 @@ docs/_build/ # Autoenv .env + +# GAE +google +google/ +google_appengine/ +google_appengine_*.zip From 4e51b5662b1c37d5e55d645ca48f10ead4df807a Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 19:44:47 -0700 Subject: [PATCH 05/10] Add basic tests for environ.py --- tests/test_environ.py | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/test_environ.py b/tests/test_environ.py index cf963a2..968bc70 100755 --- a/tests/test_environ.py +++ b/tests/test_environ.py @@ -51,6 +51,34 @@ def test_namespace_functions(self): assert namespace_manager.get_namespace == environ.get_namespace assert namespace_manager.google_apps_namespace == environ.google_apps_namespace + def test_get_environ_dict(self): + # TODO(eric): This one is a bit hefty. + pass + + def test_get_dot_target_name(self): + val = environ.get_dot_target_name() + assert val == 'testbed-version-dot-default', repr(val) + + def test_is_host_google(self): + val = environ.is_host_google() + assert val == False, repr(val) + + def test_is_development(self): + val = environ.is_development() + assert val == True, repr(val) + + def test_is_staging(self): + val = environ.is_staging() + assert val == False, repr(val) + + def test_is_production(self): + val = environ.is_production() + assert val == False, repr(val) + + def test_is_default_version(self): + val = environ.is_default_version() + assert val == False, repr(val) + if __name__ == '__main__': unittest.main() From 21961d8a7eb8ae3fb541ee251aa877b1a7dcfff7 Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 23:38:42 -0700 Subject: [PATCH 06/10] Add environ API to readme --- README.md | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index aa5aeb8..ec2e933 100644 --- a/README.md +++ b/README.md @@ -25,20 +25,27 @@ Usage: Feature parity with the Python `json` module functions. -`ndb_json.dumps` - -`ndb_json.dump` - -`ndb_json.loads` +* `ndb_json.dumps` +* `ndb_json.dump` +* `ndb_json.loads` Environment module ------------------ -Usage: - - from gaek import environ - - API: +* `environ.get_dot_target_name(version=None, module=None)` + Returns the current version/module in `-dot-` notation which is used by `target:` parameters. +* `environ.get_environ_dict()` + Return a dictionary of all environment keys/values. +* `environ.is_host_google()` + True if the app is being hosted from Google App Engine servers. +* `environ.is_development()` + True if the dev_appserver is running (localhost or local development server). +* `environ.is_staging(version=None)` + True if the app is hosted by Google (appspot.com) but the version is not the default. +* `environ.is_production(version=None)` + True if the app is being hosted by Google and the default version. +* `environ.is_default_version(version=None)` + True if the current or specified app version is the default. From cc990178a50e2e9fa44d0a1b845979bd9aa919f2 Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 23:39:27 -0700 Subject: [PATCH 07/10] Update readme formatting. --- README.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ec2e933..b7831c4 100644 --- a/README.md +++ b/README.md @@ -36,16 +36,17 @@ Environment module API: * `environ.get_dot_target_name(version=None, module=None)` - Returns the current version/module in `-dot-` notation which is used by `target:` parameters. + Returns the current version/module in `-dot-` notation which is used by `target:` parameters. * `environ.get_environ_dict()` - Return a dictionary of all environment keys/values. + Return a dictionary of all environment keys/values. * `environ.is_host_google()` - True if the app is being hosted from Google App Engine servers. + True if the app is being hosted from Google App Engine servers. * `environ.is_development()` - True if the dev_appserver is running (localhost or local development server). + True if the dev_appserver is running (localhost or local development server). * `environ.is_staging(version=None)` - True if the app is hosted by Google (appspot.com) but the version is not the default. + True if the app is hosted by Google (appspot.com) but the version is not the default. * `environ.is_production(version=None)` - True if the app is being hosted by Google and the default version. + True if the app is being hosted by Google and the default version. * `environ.is_default_version(version=None)` - True if the current or specified app version is the default. + True if the current or specified app version is the default. + From 07a51e6dc69c80f320fb472e6f07ef7218a20271 Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 23:42:29 -0700 Subject: [PATCH 08/10] More formatting. --- README.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b7831c4..53b62c3 100644 --- a/README.md +++ b/README.md @@ -36,17 +36,31 @@ Environment module API: * `environ.get_dot_target_name(version=None, module=None)` - Returns the current version/module in `-dot-` notation which is used by `target:` parameters. + + Returns the current version/module in `-dot-` notation which is used by `target:` parameters. + * `environ.get_environ_dict()` - Return a dictionary of all environment keys/values. + + Return a dictionary of all environment keys/values. + * `environ.is_host_google()` - True if the app is being hosted from Google App Engine servers. + + True if the app is being hosted from Google App Engine servers. + * `environ.is_development()` - True if the dev_appserver is running (localhost or local development server). + + True if the dev_appserver is running (localhost or local development server). + * `environ.is_staging(version=None)` - True if the app is hosted by Google (appspot.com) but the version is not the default. + + True if the app is hosted by Google (appspot.com) but the version is not the default. + * `environ.is_production(version=None)` - True if the app is being hosted by Google and the default version. + + True if the app is being hosted by Google and the default version. + * `environ.is_default_version(version=None)` - True if the current or specified app version is the default. + + True if the current or specified app version is the default. + From c79ea3afff8d254bd999f96b120acc584390dd1f Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 23:53:02 -0700 Subject: [PATCH 09/10] Update links. --- README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/README.md b/README.md index 53b62c3..05f55b1 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ GAEK: Google App Engine Kit A collection of useful tools for Python apps running on Google App Engine. * Free software: BSD license -* Documentation: https://gaek.readthedocs.org. +* Documentation: http://erichiggins.github.io/gaek/ NDB JSON module --------------- @@ -33,8 +33,6 @@ Feature parity with the Python `json` module functions. Environment module ------------------ -API: - * `environ.get_dot_target_name(version=None, module=None)` Returns the current version/module in `-dot-` notation which is used by `target:` parameters. From 4b0d099a5c6af4b946d34fbe777790969fd3500b Mon Sep 17 00:00:00 2001 From: Eric Higgins Date: Mon, 12 Oct 2015 23:58:54 -0700 Subject: [PATCH 10/10] Bump version to 0.2.0 --- CHANGELOG.md | 5 +++++ VERSION | 2 +- gaek/__init__.py | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7294593..ed407b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.2.0 +==== +- Added the `environ` module. + + 0.1.2 ===== - Actually fix the MANIFEST.in contents. diff --git a/VERSION b/VERSION index d917d3e..0ea3a94 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.1.2 +0.2.0 diff --git a/gaek/__init__.py b/gaek/__init__.py index 7c9cc1a..9f343ab 100755 --- a/gaek/__init__.py +++ b/gaek/__init__.py @@ -2,4 +2,4 @@ __author__ = 'Eric Higgins' __email__ = 'erichiggins@gmail.com' -__version__ = '0.1.2' +__version__ = '0.2.0'