Skip to content

Commit

Permalink
Merge branch 'release/0.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
erichiggins committed Oct 13, 2015
2 parents 9d8735f + 4b0d099 commit 69eb2d6
Show file tree
Hide file tree
Showing 8 changed files with 317 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -55,3 +55,9 @@ docs/_build/

# Autoenv
.env

# GAE
google
google/
google_appengine/
google_appengine_*.zip
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
0.2.0
====
- Added the `environ` module.


0.1.2
=====
- Actually fix the MANIFEST.in contents.
Expand Down
46 changes: 37 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
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.

* Free software: BSD license
* Documentation: https://gaek.readthedocs.org.
* Documentation: http://erichiggins.github.io/gaek/

NDB JSON module
---------------
Expand All @@ -29,8 +25,40 @@ Usage:

Feature parity with the Python `json` module functions.

`ndb_json.dumps`
* `ndb_json.dumps`
* `ndb_json.dump`
* `ndb_json.loads`


Environment module
------------------

* `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.

`ndb_json.dump`

`ndb_json.loads`
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.2
0.2.0
2 changes: 1 addition & 1 deletion gaek/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

__author__ = 'Eric Higgins'
__email__ = 'erichiggins@gmail.com'
__version__ = '0.1.2'
__version__ = '0.2.0'
181 changes: 181 additions & 0 deletions gaek/environ.py
Original file line number Diff line number Diff line change
@@ -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',
)),
}
84 changes: 84 additions & 0 deletions tests/test_environ.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
#!/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 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
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()

0 comments on commit 69eb2d6

Please sign in to comment.