Skip to content

Instantly share code, notes, and snippets.

@andrewdyates
Created August 14, 2010 03:52
Show Gist options
  • Save andrewdyates/523937 to your computer and use it in GitHub Desktop.
Save andrewdyates/523937 to your computer and use it in GitHub Desktop.
#!/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