Skip to content

Commit

Permalink
Release 0.4.0 (#18)
Browse files Browse the repository at this point in the history
* Added support for JSON encoding of subclasses of supported types

* Sorted the ndb types for deterministic iteration

* Add a flag fetch_models to specify the way to encode NDB keys (#11)

* Add a flag fetch_models to specify the way to encode NDB keys

* Keep backward compatibility

* Introduced flags ndb_keys_as_entities, ndb_keys_as_pairs, ndb_keys_as_urlsafe

* Covered with unit tests

* Rebased with the latest development branch and simplified the code

* Fixed documentation and test dependencies

* Fixing the key error

* Add a test that is_default_version() returns False

* Fix get_current_module_name

* All done I think

* Cleaning things up a bit

* fix typo

* remove whitespace

* Bump version to 0.4.0 for release.
  • Loading branch information
erichiggins committed Dec 7, 2017
1 parent 919aeb0 commit f3427e4
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 2 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
0.4.0
=====
- Added `_safe` methods for functions which break outside of the GAE environment.

0.3.0
=====
- Added support for encoding `ndb.Key` objects as entities, pairs, or urlsafe-strings.
Expand Down
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ Environment module

Returns the current version/module in `-dot-` notation which is used by `target:` parameters.

* `environ.get_dot_target_name_safe(version=None, module=None)`

Same as `environ.get_dot_target_name`, but this function returns `None` if there is no version or module found.

* `environ.get_environ_dict()`

Return a dictionary of all environment keys/values.
Expand All @@ -116,12 +120,30 @@ Environment module

True if the app is hosted by Google (appspot.com) but the version is not the default.

* `environ.is_staging_safe(version=None)`

Same as `environ.is_staging`, but returns `None` if there is no version found.

* `environ.is_production(version=None)`

True if the app is being hosted by Google and the default version.

* `environ.is_production_safe(version=None)`

Same as `environ.is_production`, but returns `None` if there is no version found.

* `environ.is_default_version(version=None)`

True if the current or specified app version is the default.

* `environ.is_default_version_safe(version=None)`

Same as `environ.is_default_version`, but returns `None` if there is no version found.

* `environ.get_current_version_name_safe()`

Wrapper around `google.appengine.api.modules.get_current_version_name`. Returns `None` if there is any error raised, otherwise it returns the current version name.

* `environ.get_current_module_name_safe()`

Wrapper around `google.appengine.api.modules.get_current_module_name`. Returns `None` if there is any error raised, otherwise it returns the current version name.
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.0
0.4.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.3.0'
__version__ = '0.4.0'
57 changes: 57 additions & 0 deletions gaek/environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,18 @@
'google_apps_namespace',
# Helper functions.
'get_dot_target_name',
'get_dot_target_name_safe',
'get_environ_dict',
'is_host_google',
'is_development',
'is_staging',
'is_staging_safe',
'is_production',
'is_production_safe',
'is_default_version',
'is_default_version_safe',
'get_current_module_name_safe',
'get_current_version_name_safe'
)


Expand Down Expand Up @@ -84,6 +90,20 @@


# Helper functions.
def get_current_version_name_safe():
"""Returns the current version of the app, or None if there is no current version found."""
try:
return modules.get_current_version_name()
except KeyError:
return None


def get_current_module_name_safe():
"""Returns the current module of the app, or None if there is no current module found.."""
try:
return modules.get_current_module_name()
except KeyError:
return None


def is_host_google():
Expand All @@ -97,6 +117,15 @@ def is_default_version(version=None):
return version == get_default_version()


def is_default_version_safe(version=None):
"""
True if the current or specified app version is the default.
Returns False when there is no version found.
"""
version = version or get_current_version_name_safe()
return version == 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')
Expand All @@ -107,18 +136,46 @@ def is_staging(version=None):
return is_host_google() and not is_default_version(version)


def is_staging_safe(version=None):
"""True if the app is hosted by Google (appspot.com) but the version is not the default."""
is_default_version = is_default_version_safe()
if is_default_version is None:
return False
return is_host_google() and not is_default_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 is_production_safe(version=None):
"""True if the app is being hosted by Google and the default version."""
is_default_version = is_default_version_safe(version)
if is_default_version is None:
return False
return is_host_google() and is_default_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_dot_target_name_safe(version=None, module=None):
"""
Returns the current version/module in -dot- notation which is used by `target:` parameters.
If there is no current version or module then None is returned.
"""
version = version or get_current_version_name_safe()
module = module or get_current_module_name_safe()
if version and module:
return '-dot-'.join((version, module))
return None


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}
Expand Down
70 changes: 70 additions & 0 deletions tests/test_environ.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
Tests for `environ` module.
"""

import mock
import os
import unittest

Expand Down Expand Up @@ -58,6 +59,16 @@ def test_get_dot_target_name(self):
val = environ.get_dot_target_name()
assert val == 'testbed-version-dot-default', repr(val)

def test_get_dot_target_name_safe(self):
with mock.patch('gaek.environ.get_current_version_name_safe', return_value=None):
val = environ.get_dot_target_name_safe()
assert val is None, val
with mock.patch('gaek.environ.get_current_module_name_safe', return_value=None):
val = environ.get_dot_target_name_safe()
assert val is None, val
val = environ.get_dot_target_name_safe()
assert val == 'testbed-version-dot-default', repr(val)

def test_is_host_google(self):
val = environ.is_host_google()
assert val == False, repr(val)
Expand All @@ -70,14 +81,73 @@ def test_is_staging(self):
val = environ.is_staging()
assert val == False, repr(val)

def test_is_staging_safe(self):
with mock.patch('gaek.environ.get_current_version_name_safe', return_value=None):
val = environ.is_staging_safe()
assert val is False, repr(val)
val = environ.is_staging_safe()
assert val == False, repr(val)

def test_is_production(self):
val = environ.is_production()
assert val == False, repr(val)

def test_is_production_safe(self):
with mock.patch('gaek.environ.get_current_version_name_safe', return_value=None):
val = environ.is_production_safe()
assert val is False, repr(val)
val = environ.is_production_safe()
assert val == False, repr(val)

def test_is_default_version(self):
val = environ.is_default_version()
assert val == False, repr(val)

def test_is_default_version_safe(self):
with mock.patch('gaek.environ.get_current_version_name_safe', return_value=None):
val = environ.is_default_version_safe()
assert val == False, repr(val)

def test_get_current_version_name_safe(self):
# The version is stored in an environment variable 'CURRENT_VERSION_ID'.
# If that variable isn't present then an error will be raised unless we catch it.
saved_version = os.environ.pop('CURRENT_VERSION_ID', None)

version = 'v1'
try:
version = environ.get_current_version_name_safe()
except Exception as err:
self.fail('Unexpected exception when getting current version: {}'.format(
err.message))
assert version is None

os.environ['CURRENT_VERSION_ID'] = saved_version

# Now the environment variable is back.
version = environ.get_current_version_name_safe()
assert 'testbed-version' == version, version

def test_get_current_module_name_safe(self):
"""
Test that environ.get_current_module_name returns None when there is no
current module, rather than raising an error.
"""
# The current module is stored in an environment variable 'CURRENT_MODULE_ID'.
saved_module_name = os.environ.pop('CURRENT_MODULE_ID', None)

current_module = 'v1-app'
try:
current_module = environ.get_current_module_name_safe()
except Exception as err:
self.fail('Unexpected exception when getting current module: {}'.format(
err.message))
assert current_module is None

os.environ['CURRENT_MODULE_ID'] = saved_module_name
# Now the environment variable is back.
current_module = environ.get_current_module_name_safe()
assert 'default' == current_module, current_module


if __name__ == '__main__':
unittest.main()

0 comments on commit f3427e4

Please sign in to comment.