Created
August 14, 2010 03:52
-
-
Save andrewdyates/523937 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python2.5 | |
# -*- coding: utf-8 -*- | |
# Copyright © 2010 Andrew D. Yates | |
# All Rights Reserved | |
"""Assorted Google App Engine Python Utilities. | |
ID: random string for IDs | |
KeyPath: human readable path of an app engine datastore key | |
Cookie: generate HTTP cookie header formatted string | |
""" | |
__authors__ = ['"Andrew D. Yates" <andrew.yates@hhmds.com>'] | |
import base64 | |
import datetime | |
import os | |
import re | |
def is_dev(): | |
"""Return if the environment is a developement server""" | |
return os.environ['SERVER_SOFTWARE'].find('Development') == 0 | |
class ID(basestring): | |
"""Random string ID in url-safe base64 alphabet.""" | |
def __new__(cls, bytes=66): | |
"""Return new ID. | |
Args: | |
bytes: size in bytes of ID | |
Returns: | |
str: new random string ID of length about 4/3 * len(bytes) | |
""" | |
return base64.urlsafe_b64encode(os.urandom(bytes)) | |
class KeyPath(basestring): | |
"""Plain Text representation of complete db.Key path. | |
Use KeyPaths for regex key filters and debugging. | |
db.Key paths have the form: | |
"app-name;Parent,parentname:Model,keyname:" | |
with: | |
zero or more parents in descendant order | |
characters [\#:;,] escaped with '\' prefix | |
integers printed as '#'+str(int) | |
""" | |
def __new__(cls, key): | |
"""Return encoded key path from db.Key for permission filters. | |
Args: | |
key: `db.Key` instance | |
Returns: | |
str: of encoded `key` | |
""" | |
path = [] | |
app = "%s;" % cls.encode(key.app()) | |
while key: | |
kind = cls.encode(key.kind()) | |
name = cls.encode(key.id_or_name()) | |
entity = "%s,%s:" % (kind, name) | |
path.append(entity) | |
key = key.parent() | |
path.append(app) | |
path.reverse() | |
return ''.join(path) | |
@staticmethod | |
def encode(value): | |
"""Return encoded key part. | |
for string: Escape chars in [\#:;,] with backslashes | |
for int: prepend with # as string | |
Args: | |
s: value to escape, either int or str | |
Returns | |
str of s with escaped characters | |
""" | |
RE_ESCAPED = re.compile(r'[\#:;,]') | |
if isinstance(value, basestring): | |
encoded = RE_ESCAPED.sub(lambda x: '\%s' % x.group(0), value) | |
else: | |
encoded = '#%s' % value | |
return encoded | |
class Cookie(basestring): | |
"""HTTP Header `Set-Cookie` value.""" | |
DATE_STRF = "%a %d-%b-%Y %H:%M:%S GMT" | |
DAYS = 30 | |
def __new__(cls, key, value, *args, **kwds): | |
"""Return Cookie string for key=value. | |
Args: | |
key: str of cookie key | |
value: str of cookie value | |
Keywords: | |
days: int of days until cookie expires | |
path: str relative path | |
domain: str of cookie domain | |
secure: str of 'secure' or '' | |
httponly: str of 'httponly' or '' | |
Returns: | |
str: new cookie of key=value with parameters | |
""" | |
now = datetime.datetime.utcnow() | |
expires = now + datetime.timedelta(days=kwds.get('days', cls.DAYS)) | |
morsels = [ | |
"%s=%s" % (key, value), | |
"expires=%s" % expires.strftime(cls.DATE_STRF), | |
"path=%s" % kwds.get('path', '/'), | |
] | |
if not is_dev(): | |
morsels.extend([ | |
"domain=%s" % kwds.get('domain', '.'+os.environ['SERVER_NAME']), | |
"%s" % kwds.get('secure', 'secure'), | |
"%s" % kwds.get('httponly', 'httponly'), | |
]) | |
return '; '.join(filter(None, morsels)) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment