Skip to content
Browse files

Cleaned up Tweetapp and now with POST support thanks to @nlehuen.

  • Loading branch information...
1 parent 15d2c18 commit 7530186499c60ffe28bdea7a7e6bdd8fc48da005 @tav committed May 22, 2009
Showing with 0 additions and 14,837 deletions.
  1. +0 −36 app/app.yaml.in
  2. +0 −11 app/index.yaml
  3. +0 −1,077 app/root.py
  4. 0 app/source/__init__.py
  5. +0 −2,138 app/third_party/demjson.py
  6. +0 −286 app/third_party/format_traceback.py
  7. +0 −33 app/third_party/genshi/__init__.py
  8. +0 −357 app/third_party/genshi/builder.py
  9. +0 −712 app/third_party/genshi/core.py
  10. +0 −20 app/third_party/genshi/filters/__init__.py
  11. +0 −392 app/third_party/genshi/filters/html.py
  12. +0 −596 app/third_party/genshi/filters/i18n.py
  13. +0 −1,309 app/third_party/genshi/filters/transform.py
  14. +0 −441 app/third_party/genshi/input.py
  15. +0 −761 app/third_party/genshi/output.py
  16. +0 −1,174 app/third_party/genshi/path.py
  17. +0 −23 app/third_party/genshi/template/__init__.py
  18. +0 −446 app/third_party/genshi/template/_ast24.py
  19. +0 −506 app/third_party/genshi/template/ast24.py
  20. +0 −104 app/third_party/genshi/template/astgae.py
  21. +0 −778 app/third_party/genshi/template/astutil.py
  22. +0 −632 app/third_party/genshi/template/base.py
  23. +0 −733 app/third_party/genshi/template/directives.py
  24. +0 −617 app/third_party/genshi/template/eval.py
  25. +0 −151 app/third_party/genshi/template/interpolation.py
  26. +0 −334 app/third_party/genshi/template/loader.py
  27. +0 −401 app/third_party/genshi/template/markup.py
  28. +0 −175 app/third_party/genshi/template/plugin.py
  29. +0 −333 app/third_party/genshi/template/text.py
  30. +0 −245 app/third_party/genshi/util.py
  31. +0 −10 bin/run.sh
  32. +0 −6 bin/update.sh
  33. 0 {old → standalone}/twitter_oauth_handler.py
View
36 app/app.yaml.in
@@ -1,36 +0,0 @@
-application: yourapp
-version: 1
-runtime: python
-api_version: 1
-
-# default_expiration: "3d 3h"
-
-handlers:
-
-- url: /favicon.ico
- static_files: static/favicon.ico
- upload: static/favicon.ico
-
-- url: /robots.txt
- static_files: static/robots.txt
- upload: static/robots.txt
-
-- url: /.get-static-file/js
- static_dir: static/js
- expiration: 7d
-
-- url: /.get-static-file/css
- static_dir: static/css
- expiration: 7d
-
-- url: /.get-static-file/gfx
- static_dir: static/gfx
- expiration: 7d
-
-- url: /manage/.*
- script: manage.py
- login: admin
-
-- url: .*
- script: root.py
-
View
11 app/index.yaml
@@ -1,11 +0,0 @@
-indexes:
-
-# AUTOGENERATED
-
-# This index.yaml is automatically updated whenever the dev_appserver
-# detects that a new type of query is run. If you want to manage the
-# index.yaml file manually, remove the above marker line (the line
-# saying "# AUTOGENERATED"). If you want to manage some indexes
-# manually, move them above the marker line. The index.yaml file is
-# automatically uploaded to the admin console when you next deploy
-# your application using appcfg.py.
View
1,077 app/root.py
@@ -1,1077 +0,0 @@
-"""TweetApp Framework."""
-
-# Released into the Public Domain by tav@espians.com
-
-import logging
-import os
-import sys
-
-from BaseHTTPServer import BaseHTTPRequestHandler
-from cgi import parse_qsl as parse_query_string
-from Cookie import SimpleCookie
-from datetime import datetime, timedelta
-from hashlib import sha1
-from hmac import new as hmac
-from os.path import dirname, join as join_path, getmtime
-from pprint import pprint
-from re import compile as compile_regex
-from random import getrandbits
-from StringIO import StringIO
-from time import time
-from traceback import format_exception
-from urllib import urlencode, quote as urlquote, unquote as urlunquote
-from uuid import uuid4
-from wsgiref.headers import Headers
-
-# ------------------------------------------------------------------------------
-# extend sys.path to include the ``third_party`` lib direktory
-# ------------------------------------------------------------------------------
-
-APP_DIRECTORY = dirname(__file__)
-
-sys.path.insert(0, join_path(APP_DIRECTORY, 'third_party'))
-
-# ------------------------------------------------------------------------------
-# import other libraries
-# ------------------------------------------------------------------------------
-
-from demjson import decode as decode_json
-from format_traceback import HTMLExceptionFormatter
-from genshi.core import Markup
-from genshi.template import MarkupTemplate, TextTemplate, TemplateLoader
-from webob import Request as WebObRequest
-
-from google.appengine.api.urlfetch import fetch as urlfetch, GET, POST
-from google.appengine.ext import db
-
-from source.config import *
-
-# ------------------------------------------------------------------------------
-# exseptions
-# ------------------------------------------------------------------------------
-
-class Error(Exception):
- """Base TweetApp Exception."""
-
-class Redirect(Error):
- """
- Redirection Error.
-
- This is used to handle both internal and HTTP redirects.
-
- """
-
- def __init__(self, uri, method=None, permanent=False):
- self.uri = uri
- self.method = method
- self.permanent = permanent
-
-class UnAuth(Error):
- """Unauthorised."""
-
-class NotFound(Error):
- """404."""
-
-class ReturnValue(Error):
- """Service return value."""
-
-def format_traceback(type, value, traceback, limit=200):
- return HTMLExceptionFormatter(limit).formatException(type, value, traceback)
-
-# ------------------------------------------------------------------------------
-# i/o helpers
-# ------------------------------------------------------------------------------
-
-class DevNull:
- """Provide a file-like interface emulating /dev/null."""
-
- def __call__(self, *args, **kwargs):
- pass
-
- def flush(self):
- pass
-
- def log(self, *args, **kwargs):
- pass
-
- def write(self, input):
- pass
-
-DEVNULL = DevNull()
-
-# ------------------------------------------------------------------------------
-# wsgi
-# ------------------------------------------------------------------------------
-
-SSL_ENABLED_FLAGS = frozenset(['yes', 'on', '1'])
-
-def run_wsgi_app(application, ssl_enabled_flags=SSL_ENABLED_FLAGS):
- """Run a WSGI ``application`` inside a CGI environment."""
-
- environ = dict(os.environ)
-
- environ['wsgi.errors'] = sys.stderr
- environ['wsgi.input'] = sys.stdin
- environ['wsgi.multiprocess'] = False
- environ['wsgi.multithread'] = False
- environ['wsgi.run_once'] = True
- environ['wsgi.version'] = (1, 0)
-
- if environ.get('HTTPS') in ssl_enabled_flags:
- environ['wsgi.url_scheme'] = 'https'
- else:
- environ['wsgi.url_scheme'] = 'http'
-
- sys._boot_stdout = sys.stdout
- sys.stdout = DEVNULL
- write = sys._boot_stdout.write
-
- try:
- result = application(environ, start_response)
- if result is not None:
- for data in result:
- write(data)
- finally:
- sys.stdout = sys._boot_stdout
-
-def start_response(status, response_headers, exc_info=None):
- """Initialise a WSGI response with the given status and headers."""
-
- if exc_info:
- try:
- raise exc_info[0], exc_info[1], exc_info[2]
- finally:
- exc_info = None # bye-bye sirkular ref
-
- write = sys._boot_stdout.write
- write("Status: %s\r\n" % status)
-
- for name, val in response_headers:
- write("%s: %s\r\n" % (name, val))
-
- write('\r\n')
-
- return write
-
-# ------------------------------------------------------------------------------
-# general http util
-# ------------------------------------------------------------------------------
-
-def get_http_datetime(timestamp=None):
- """Return an HTTP header date/time string."""
-
- if timestamp:
- if not isinstance(timestamp, datetime):
- timestamp = datetime.fromtimestamp(timestamp)
- else:
- timestamp = datetime.utcnow()
-
- return timestamp.strftime('%a, %d %B %Y %H:%M:%S GMT') # %m
-
-# ------------------------------------------------------------------------------
-# http response
-# ------------------------------------------------------------------------------
-
-HTTP_STATUS_MESSAGES = BaseHTTPRequestHandler.responses
-
-class Response(object):
- """HTTP Response."""
-
- def __init__(self):
- self.cookies = {}
- self.status = []
- self.stream = StringIO()
- self.write = self.stream.write
- self.raw_headers = []
- self.headers = Headers(self.raw_headers)
- self.set_header = self.headers.__setitem__
-
- def set_response_status(self, code, message=None):
- if not message:
- if not HTTP_STATUS_MESSAGES.has_key(code):
- raise Error('Invalid HTTP status code: %d' % code)
- message = HTTP_STATUS_MESSAGES[code][0]
- self.status[:] = (code, message)
-
- def clear_response(self):
- self.stream.seek(0)
- self.stream.truncate(0)
-
- def set_status_and_clear_response(self, code):
- self.set_response_status(code)
- self.clear_response()
-
- def set_cookie(self, name, value, **kwargs):
- cookie = self.cookies.setdefault(name, {})
- cookie['value'] = value
- kwargs.setdefault('path', '/')
- for name, value in kwargs.iteritems():
- if value:
- cookie[name.lower()] = value
-
- def append_to_cookie(self, name, value):
- cookie = self.cookies.setdefault(name, {})
- if 'value' in cookie:
- cookie['value'] = '%s:%s' % (cookie['value'], value)
- else:
- cookie['value'] = value
-
- def expire_cookie(self, name, **kwargs):
- if name in self.cookies:
- del self.cookies[name]
- kwargs.setdefault('path', '/')
- kwargs.update({'max_age': 0, 'expires': "Fri, 31-Dec-99 23:59:59 GMT"})
- self.set_cookie(name, 'deleted', **kwargs) # @/@ 'deleted' or just '' ?
-
- def set_to_not_cache_response(self):
- headers = self.headers
- headers['Expires'] = "Fri, 31 December 1999 23:59:59 GMT"
- headers['Last-Modified'] = get_http_datetime()
- headers['Cache-Control'] = "no-cache, must-revalidate" # HTTP/1.1
- headers['Pragma'] = "no-cache" # HTTP/1.0
-
-# ------------------------------------------------------------------------------
-# kookie support
-# ------------------------------------------------------------------------------
-
-COOKIE_KEY_NAMES = frozenset([
- 'domain', 'expires', 'httponly', 'max-age', 'path', 'secure', 'version'
- ])
-
-def get_cookie_headers_to_write(cookies, valid_keys=COOKIE_KEY_NAMES):
- """Return HTTP response headers for the given ``cookies``."""
-
- output = SimpleCookie()
-
- for name, values in cookies.iteritems():
-
- name = str(name)
- output[name] = values.pop('value')
- cur = output[name]
-
- for key, value in values.items():
- if key == 'max_age':
- key = 'max-age'
- # elif key == 'comment':
- # # encode rather than throw an exception
- # v = quote(v.encode('utf-8'), safe="/?:@&+")
- if key not in valid_keys:
- continue
- cur[key] = value
-
- return str(output)
-
-# ------------------------------------------------------------------------------
-# kore wsgi applikation
-# ------------------------------------------------------------------------------
-
-HTTP_HANDLERS = {}
-register_http_handler = HTTP_HANDLERS.__setitem__
-
-def Application(environ, start_response, handlers=HTTP_HANDLERS):
- """Core WSGI Application."""
-
- env_copy = dict(environ)
- response = Response()
-
- http_method = environ['REQUEST_METHOD']
-
- try:
-
- if http_method in handlers:
- response.headers['Content-Type'] = 'text/html; charset=utf-8'
- response.headers['Cache-Control'] = 'no-cache'
- response.set_response_status(200)
- handlers[http_method](environ, response)
- else:
- response.set_status_and_clear_response(501)
-
- except Redirect, redirect:
-
- # internal redirekt
- if redirect.method:
- env_copy['REQUEST_METHOD'] = redirect.method
- if '?' in redirect.uri:
- (env_copy['PATH_INFO'],
- env_copy['QUERY_STRING']) = redirect.uri.split('?', 1)
- else:
- env_copy['PATH_INFO'] = redirect.uri
- env_copy['QUERY_STRING'] = ''
- return Application(
- env_copy, start_response, handlers, response_factory
- )
-
- # external redirekt
- if redirect.permanent:
- response.set_response_status(301)
- else:
- response.set_response_status(302)
-
- response.headers['Location'] = str(
- urljoin('', redirect.uri)
- )
- response.clear_response()
-
- except Exception, exception:
-
- response.set_status_and_clear_response(500)
- lines = ''.join(format_exception(*sys.exc_info()))
- logging.error(lines)
-
- if DEBUG_MODE:
- response.headers['Content-Type'] = 'text/plain'
- response.write(lines)
-
- return
-
- content = response.stream.getvalue()
-
- if isinstance(content, unicode):
- content = content.encode('utf-8')
- elif response.headers.get('Content-Type', '').endswith('; charset=utf-8'):
- try:
- content.decode('utf-8')
- except UnicodeError, error:
- logging.warning('Response written is not UTF-8: %s', error)
-
- response.headers['Content-Length'] = str(len(content))
-
- raw_headers = response.raw_headers + [
- ('Set-Cookie', ck.split(' ', 1)[-1])
- for ck in get_cookie_headers_to_write(response.cookies).split('\r\n')
- ]
-
- write = start_response('%d %s' % tuple(response.status), raw_headers)
-
- if http_method != 'HEAD':
- write(content)
-
- response.stream.close()
-
- return [''] # @/@ why do we have this instead of None ??
-
-# ------------------------------------------------------------------------------
-# http request objekt
-# ------------------------------------------------------------------------------
-
-VALID_CHARSETS = frozenset(['utf-8'])
-find_charset = compile_regex(r'(?i);\s*charset=([^;]*)').search
-
-class RequestAPI(object):
- """HTTP Request."""
-
- def __init__(
- self, environ, response, parse_query_string=parse_query_string,
- find_charset=find_charset, urlunquote=urlunquote
- ):
-
- self.service_name = ''
- self.request_method = environ['REQUEST_METHOD']
-
- self.environ = environ
- self.response = response
-
- self.append_to_cookie = response.append_to_cookie
- self.expire_cookie = response.expire_cookie
- self.set_cookie = response.set_cookie
- self.clear_response = response.clear_response
- self.Redirect = Redirect
- self.response_headers = response.headers
- self.set_response_header = response.set_header
- self.set_response_status = response.set_response_status
- self.set_status_and_clear_response = response.set_status_and_clear_response
- self.set_to_not_cache_response = response.set_to_not_cache_response
-
- path = environ['PATH_INFO']
- query = environ['QUERY_STRING']
- scheme = environ['wsgi.url_scheme']
- port = environ['SERVER_PORT']
-
- self.site_uri = (
- scheme + '://' + environ['SERVER_NAME'] + ((
- (scheme == 'http' and port != '80') or
- (scheme == 'https' and port != '443')
- ) and ':%s' % port or '')
- )
-
- self.uri = self.site_uri + path
- self.uri_with_qs = self.uri + (query and '?' or '') + query
-
- self.request_charset = 'utf-8'
-
- request_content_type = environ.get('CONTENT-TYPE', '')
-
- if request_content_type:
- match = find_charset(request_content_type)
- if match:
- match = match.group(1).lower()
- if match in VALID_CHARSETS:
- self.request_charset = match
-
-
- self.request_args = tuple(
- unicode(arg, self.request_charset, 'strict')
- for arg in path.split('/') if arg
- )
-
- self.request_flags = flags = set()
- self.request_kwargs = kwargs = {}
-
- _val = None
-
- for part in [
- sub_part
- for part in query.lstrip('?').split('&')
- for sub_part in part.split(';')
- ]:
- if not part:
- continue
- part = part.split('=', 1)
- if len(part) == 1:
- flags.add(urlunquote(part[0].replace('+', ' ')))
- continue
- key = urlunquote(part[0].replace('+', ' '))
- value = part[1]
- if value:
- value = unicode(
- urlunquote(value.replace('+', ' ')),
- request_charset, 'strict'
- )
- else:
- value = None
- if key in kwargs:
- _val = kwargs[key]
- if isinstance(_val, list):
- _val.append(value)
- else:
- kwargs[key] = [_val, value]
- continue
- kwargs[key] = value
-
- self.cookies = cookies = {}
- cookie_data = environ.get('HTTP_COOKIE', '')
-
- if cookie_data:
- _parsed = SimpleCookie()
- _parsed.load(_data)
- for name in _parsed:
- cookies[name] = _parsed[name].value
-
- def compute_site_uri(self, *args, **kwargs):
-
- request_charset = self.request_charset
-
- out = self.site_uri + '/' + '/'.join(
- arg.encode(request_charset) for arg in args
- )
-
- if kwargs:
- out += '?'
- _set = 0
- _l = ''
- for key, value in kwargs.items():
- key = urlquote(key).replace(' ', '+')
- if value is None:
- value = ''
- if isinstance(value, list):
- for val in value:
- if _set: _l = '&'
- out += '%s%s=%s' % (
- _l, key,
- urlquote(val.encode(request_charset)).replace(' ', '+')
- )
- _set = 1
- else:
- if _set: _l = '&'
- out += '%s%s=%s' % (
- _l, key, quote(value.encode(request_charset)).replace(' ', '+')
- )
- _set = 1
-
- return out
-
- def get_cookie(self, name, default=''):
- return self.cookies.get(name, default)
-
- def get_current_user(self): # @/@
- return player
-
- def get_current_user_id(self): # @/@
- return player_uuid
-
- def get_request_object(self):
- return WebObRequest(self.environ)
-
- def pretty_print(self, object):
- stream = StringIO()
- pprint(object, stream)
- self.response.write(stream.getvalue())
-
- def out(self, arg): # *args
- if isinstance(arg, str):
- self.response.write(arg)
- elif isinstance(arg, unicode):
- self.response.write(arg.encode('utf-8'))
- else:
- self.response.write(str(arg))
-
-# ------------------------------------------------------------------------------
-# servise registries and builtins
-# ------------------------------------------------------------------------------
-
-SERVICE_REGISTRY = {}
-SLOT_REGISTRY = {}
-RENDERER_REGISTRY = {}
-TITLE_REGISTRY = {}
-
-BUILTINS = {
- 'DEBUG_MODE': DEBUG_MODE,
- 'STATIC': SITE_STATIC_URL,
- 'Markup': Markup,
- 'content_slot': '',
- 'urlencode': urlencode,
- 'urlquote': urlquote,
- }
-
-# ------------------------------------------------------------------------------
-# http request handlers
-# ------------------------------------------------------------------------------
-
-SUPPORTED_HTTP_METHODS = ('OPTIONS', 'GET', 'HEAD', 'POST', 'DELETE')
-
-def handle_http_request(environ, response, builtins=BUILTINS):
- """Handle generic HTTP requests."""
-
- api = RequestAPI(environ, response)
-
- # api.set_response_header('Content-Type', 'text/plain; charset=utf-8')
- # api.pretty_print(environ)
- # api.out('\n\n')
-
- if environ['REQUEST_METHOD'] == 'POST':
- # handle CSRF token
- transactions_enabled = 1
-
- args, kwargs = api.request_args, api.request_kwargs
-
- if 'submit' in kwargs:
- del kwargs['submit']
-
- service_name = 'core.render_object'
- format = 'html'
- slot_only = False
-
- if args and args[0].startswith('.'):
- service_name = args[0].lstrip('.')
- args = args[1:]
-
- if args and args[-1] in ('index.rss', 'index.json'):
- format = args[-1].split('.')[-1]
- args = args[:-1]
-
- if args and args[-1] == '_slot_only':
- slot_only = True
- args = args[:-1]
-
- page_title = ''
- kwargs.update(builtins)
-
- try:
-
- if service_name not in SERVICE_REGISTRY:
- raise NotFound(service_name)
-
- api.service_name = service_name
-
- service = SERVICE_REGISTRY[service_name]
- slot = SLOT_REGISTRY[service_name]
- renderer = RENDERER_REGISTRY[service_name]
- page_title = TITLE_REGISTRY[service_name]
- data = service(api, *args, **kwargs) or {}
-
- if 'finish_publishing' in data:
- return
-
- output = data.get('return_value', '')
- kwargs.update(data)
-
- if renderer:
- output = renderer(api=api, **kwargs)
-
- except NotFound, msg:
- response.set_response_status(404)
- output = ERROR_404_TEMPLATE
- slot = 'content_slot'
- except UnAuth, msg:
- response.set_response_status(401)
- output = ERROR_401_TEMPLATE % msg
- slot = 'content_slot'
- except Redirect:
- raise
- except Exception:
- response.set_response_status(500)
- logging.error(''.join(format_exception(*sys.exc_info())))
- output = ERROR_500_TEMPLATE % ''.join(format_traceback(*sys.exc_info()))
- slot = 'content_slot'
-
- if not environ.get('HTTP_X_REQUESTED_WITH') and (not slot_only):
- kwargs[slot] = output
- kwargs['page_title'] = page_title
- output = render_genshi_template('main', api=api, **kwargs)
-
- api.out(output)
-
-def handle_http_options_request(environ, response):
- """Handle an HTTP OPTIONS request."""
-
- return response.set_header(
- 'Allow', ', '.join(HTTP_HANDLERS.keys())
- )
-
-register_http_handler('GET', handle_http_request)
-register_http_handler('HEAD', handle_http_request)
-register_http_handler('POST', handle_http_request)
-register_http_handler('OPTIONS', handle_http_options_request)
-
-# ------------------------------------------------------------------------------
-# kore servise dekorator
-# ------------------------------------------------------------------------------
-
-def register_service(
- name, renderer=None, slot='content_slot', validators=None, title=''
- ):
- """Decorate a function with service-enabled behaviour."""
-
- def decorate_function(func):
-
- if name in SERVICE_REGISTRY:
- raise Error("Service already exists: %r" % name)
-
- SLOT_REGISTRY[name] = slot
- TITLE_REGISTRY[name] = title
-
- if isinstance(renderer, basestring):
- _renderer = func.__name__
- else:
- _renderer = renderer
-
- RENDERER_REGISTRY[name] = _renderer
- SERVICE_REGISTRY[name] = func
-
- return func
-
- return decorate_function
-
-# ------------------------------------------------------------------------------
-# genshi template handlers
-# ------------------------------------------------------------------------------
-
-GENSHI_TEMPLATE_CACHE = {}
-
-if DEBUG_MODE:
-
- GENSHI_MTIME_DATA = {}
-
- def get_genshi_template(name, klass=MarkupTemplate):
-
- filepath = join_path(TEMPLATE_DIRECTORY, name+'.genshi')
- template_time = getmtime(filepath)
-
- if ((template_time <= GENSHI_MTIME_DATA.get(name, 0)) and
- (name in GENSHI_TEMPLATE_CACHE)):
- return GENSHI_TEMPLATE_CACHE[name]
-
- template = klass(open(filepath, 'U'), filepath, name)
-
- GENSHI_TEMPLATE_CACHE[name] = template
- GENSHI_MTIME_DATA[name] = template_time
-
- return template
-
-else:
-
- def get_genshi_template(name, klass=MarkupTemplate):
-
- if name in GENSHI_TEMPLATE_CACHE:
- return GENSHI_TEMPLATE_CACHE[name]
-
- filepath = join_path(TEMPLATE_DIRECTORY, name+'.genshi')
- template_data = open(filepath, 'U')
-
- return GENSHI_TEMPLATE_CACHE.setdefault(
- name, klass(template_data, filepath, name)
- )
-
-def call_genshi_template(template, template_mode='xhtml', **kwargs):
- return template.generate(**kwargs).render(template_mode)
-
-def render_genshi_template(template_name, **kwargs):
- return get_genshi_template(template_name).generate(**kwargs).render('xhtml')
-
-# ------------------------------------------------------------------------------
-# text indexing
-# ------------------------------------------------------------------------------
-
-MIN_WORD_LENGTH = 3
-
-STOP_WORDS = {
-
- 'en': frozenset([
-
- 'a', 'about', 'according', 'accordingly', 'affected', 'affecting',
- # 'after',
- 'again', 'against', 'all', 'almost', 'already', 'also', 'although',
- 'always', 'am', 'among', 'an', 'and', 'any', 'anyone', 'apparently', 'are',
- 'arise', 'as', 'aside', 'at',
- # 'away',
- 'be', 'became', 'because', 'become',
- 'becomes', 'been', 'before', 'being', 'between', 'both', 'briefly', 'but',
- 'by', 'came', 'can', 'cannot', 'certain', 'certainly', 'could', 'did', 'do',
- 'does', 'done', 'during', 'each', 'either', 'else', 'etc', 'ever', 'every',
- 'following', 'for', 'found', 'from', 'further', 'gave', 'gets', 'give',
- 'given', 'giving', 'gone', 'got', 'had', 'hardly', 'has', 'have', 'having',
- 'here', 'how', 'however', 'i', "i'm", 'if', 'in', 'into', 'is', 'it', 'its',
- "it's", 'itself',
- # 'just',
- 'keep', 'kept', 'knowledge', 'largely', 'like', 'made', 'mainly',
- 'make', 'many', 'might', 'more', 'most', 'mostly', 'much', 'must', 'nearly',
- 'necessarily', 'neither', 'next', 'no', 'none', 'nor', 'normally', 'not',
- 'noted', 'now', 'obtain', 'obtained', 'of', 'often', 'on', 'only', 'or',
- 'other', 'our', 'out', 'owing', 'particularly', 'past', 'perhaps', 'please',
- 'poorly', 'possible', 'possibly', 'potentially', 'predominantly', 'present',
- 'previously', 'primarily', 'probably', 'prompt', 'promptly', 'put',
- 'quickly', 'quite', 'rather', 'readily', 'really', 'recently', 'regarding',
- 'regardless', 'relatively', 'respectively', 'resulted', 'resulting',
- 'results', 'said', 'same', 'seem', 'seen', 'several', 'shall', 'should',
- 'show', 'showed', 'shown', 'shows', 'significantly', 'similar', 'similarly',
- 'since', 'slightly', 'so', 'some', 'sometime', 'somewhat', 'soon',
- 'specifically',
- # 'state',
- 'states', 'strongly', 'substantially',
- 'successfully', 'such', 'sufficiently', 'than', 'that', 'the', 'their',
- 'theirs', 'them', 'then', 'there', 'therefore', 'these', 'they', 'this',
- 'those', 'though', 'through', 'throughout', 'to', 'too', 'toward', 'under',
- 'unless', 'until', 'up', 'upon', 'use', 'used', 'usefully', 'usefulness',
- 'using', 'usually', 'various', 'very', 'was', 'we', 'were', 'what', 'when',
- 'where', 'whether', 'which', 'while', 'who', 'whose', 'why', 'widely',
- 'will', 'with', 'within', 'without', 'would', 'yet', 'you'
- ])
-
- }
-
-# find_all_words = re.compile(r'(?u)\w+').findall # (?L)\w+
-
-find_all_words = compile_regex(
- r'[^\s!\"#$%&()*+,-./:;<=>?@\[\\^_`{|}~]*'
- ).findall
-
-HTML_PATTERNS = (
- # cdata
- compile_regex(r'<!\[CDATA\[((?:[^\]]+|\](?!\]>))*)\]\]>').sub,
- # comment
- compile_regex(r'<!--((?:[^-]|(?:-[^-]))*)-->').sub,
- # pi
- compile_regex(r'<\?(\S+)[\t\n\r ]+(([^\?]+|\?(?!>))*)\?>').sub,
- # doctype
- compile_regex(r'(?m)(<!DOCTYPE[\t\n\r ]+\S+[^\[]+?(\[[^\]]+?\])?\s*>)').sub,
- # entities
- compile_regex(r'&[A-Za-z]+;').sub,
- # tag
- compile_regex(r'(?ms)<[^>]+>').sub,
- # re.compile(r'<[^<>]*>').sub,
- )
-
-def harvest_words(
- text, ignore_html=True, min_word_length=MIN_WORD_LENGTH,
- stop_words=STOP_WORDS, html_patterns=HTML_PATTERNS,
- find_words_in_text=find_all_words
- ):
- """
- Harvest words from the given ``text``.
-
- >>> text = "hello <tag>&nbsp;world. here! there, is a ain't 'so' \
- ... it \"great hello ' '?"
-
- """ # emacs'
-
- if ignore_html:
- for replace_html in html_patterns:
- text = replace_html(' ', text)
-
- text = text.lower() # @/@ handle i18n ??
- words = set(); add_word = words.add
-
- for word in find_words_in_text(text):
-
- while word.startswith("'"):
- word = word[1:]
- while word.endswith("'"):
- word = word[:-1]
-
- if (len(word) > min_word_length) and (word not in stop_words):
- add_word(word)
-
- return list(words)
-
-# ------------------------------------------------------------------------------
-# plex link syntax
-# ------------------------------------------------------------------------------
-
-replace_links = compile_regex(r'[^\\]\[\[(.*?)[^\\]\]\]').sub
-
-def _handle_links(content):
- pass
-
-def handle_links(content):
- return replace_links(content, _handle_links)
-
-# ------------------------------------------------------------------------------
-# utility functions
-# ------------------------------------------------------------------------------
-
-def get_oauth_service_key(service, cache={}):
- if service in cache: return cache[service]
- return cache.setdefault(
- service, "%s&" % encode(OAUTH_APP_SETTINGS[service]['consumer_secret'])
- )
-
-def create_uuid():
- return 'id-%s' % uuid4()
-
-def encode(text):
- return urlquote(str(text), '')
-
-def twitter_specifier_handler(client):
- return client.get('/account/verify_credentials')['screen_name']
-
-OAUTH_APP_SETTINGS['twitter']['specifier_handler'] = twitter_specifier_handler
-
-# ------------------------------------------------------------------------------
-# oauth db entities
-# ------------------------------------------------------------------------------
-
-class OAuthRequestToken(db.Model):
- """OAuth Request Token."""
-
- service = db.StringProperty()
- oauth_token = db.StringProperty()
- oauth_token_secret = db.StringProperty()
- created = db.DateTimeProperty(auto_now_add=True)
-
-class OAuthAccessToken(db.Model):
- """OAuth Access Token."""
-
- service = db.StringProperty()
- specifier = db.StringProperty()
- oauth_token = db.StringProperty()
- oauth_token_secret = db.StringProperty()
- created = db.DateTimeProperty(auto_now_add=True)
-
-# ------------------------------------------------------------------------------
-# oauth client
-# ------------------------------------------------------------------------------
-
-class OAuthClient(object):
- """OAuth client."""
-
- __public__ = ('callback', 'cleanup', 'login', 'logout')
-
- def __init__(self, webapp_api, service, oauth_callback=None, **request_params):
- self.service = service
- self.service_info = OAUTH_APP_SETTINGS[service]
- self.service_key = None
- self.webapp_api = webapp_api
- self.request_params = request_params
- self.oauth_callback = oauth_callback
- self.token = None
- self.cookie_name = 'oauth.%s' % service
-
- # public methods
-
- def get(self, api_method, **extra_params):
-
- if not (api_method.startswith('http://') or api_method.startswith('https://')):
- api_method = '%s%s%s' % (
- self.service_info['default_api_prefix'], api_method,
- self.service_info['default_api_suffix']
- )
-
- if self.token is None:
- self.token = OAuthAccessToken.get_by_key_name(
- self.webapp_api.get_cookie(self.cookie_name)
- )
-
- fetch = urlfetch(self.get_signed_url(
- api_method, self.token, **extra_params
- ))
-
- if fetch.status_code != 200:
- raise ValueError(
- "Error calling... Got return status: %i [%r]" %
- (fetch.status_code, fetch.content)
- )
-
- return decode_json(fetch.content)
-
- def login(self):
-
- proxy_id = self.webapp_api.get_cookie(self.cookie_name)
-
- if proxy_id:
- return "FOO%rFF" % proxy_id
- self.webapp_api.expire_cookie(self.cookie_name)
-
- return self.get_request_token()
-
- def logout(self, return_to='/'):
- self.webapp_api.expire_cookie(self.cookie_name)
- raise Redirect(self.webapp_api.request_kwargs.get("return_to", return_to))
-
- # oauth workflow
-
- def get_request_token(self):
-
- token_info = self.get_data_from_signed_url(
- self.service_info['request_token_url'], **self.request_params
- )
-
- token = OAuthRequestToken(
- service=self.service,
- **dict(token.split('=') for token in token_info.split('&'))
- )
-
- token.put()
-
- if self.oauth_callback:
- oauth_callback = {'oauth_callback': self.oauth_callback}
- else:
- oauth_callback = {}
-
- raise Redirect(self.get_signed_url(
- self.service_info['user_auth_url'], token, **oauth_callback
- ))
-
- def callback(self, return_to='/'):
-
- oauth_token = self.webapp_api.request_kwargs.get("oauth_token")
-
- if not oauth_token:
- return get_request_token()
-
- oauth_token = OAuthRequestToken.all().filter(
- 'oauth_token =', oauth_token).filter(
- 'service =', self.service).fetch(1)[0]
-
- token_info = self.get_data_from_signed_url(
- self.service_info['access_token_url'], oauth_token
- )
-
- key_name = create_uuid()
-
- self.token = OAuthAccessToken(
- key_name=key_name, service=self.service,
- **dict(token.split('=') for token in token_info.split('&'))
- )
-
- if 'specifier_handler' in self.service_info:
- specifier = self.token.specifier = self.service_info['specifier_handler'](self)
- old = OAuthAccessToken.all().filter(
- 'specifier =', specifier).filter(
- 'service =', self.service)
- db.delete(old)
-
- self.token.put()
-
- self.webapp_api.set_cookie(
- self.cookie_name, key_name, expires="Fri, 31-Dec-2021 23:59:59 GMT"
- )
-
- raise Redirect(return_to)
-
- def cleanup(self):
- query = OAuthRequestToken.all().filter(
- 'created <', datetime.now() - EXPIRATION_WINDOW
- )
- count = query.count(CLEANUP_BATCH_SIZE)
- db.delete(query.fetch(CLEANUP_BATCH_SIZE))
- return "Cleaned %i entries" % count
-
- # request marshalling
-
- def get_data_from_signed_url(self, __url, __token=None, __meth='GET', **extra_params):
- return urlfetch(self.get_signed_url(
- __url, __token, __meth, **extra_params
- )).content
-
- def get_signed_url(self, __url, __token=None, __meth='GET',**extra_params):
-
- service_info = self.service_info
-
- kwargs = {
- 'oauth_consumer_key': service_info['consumer_key'],
- 'oauth_signature_method': 'HMAC-SHA1',
- 'oauth_version': '1.0',
- 'oauth_timestamp': int(time()),
- 'oauth_nonce': getrandbits(64),
- }
-
- kwargs.update(extra_params)
-
- if self.service_key is None:
- self.service_key = get_oauth_service_key(self.service)
-
- if __token is not None:
- kwargs['oauth_token'] = __token.oauth_token
- key = self.service_key + encode(__token.oauth_token_secret)
- else:
- key = self.service_key
-
- message = '&'.join(map(encode, [
- __meth.upper(), __url, '&'.join(
- '%s=%s' % (encode(k), encode(kwargs[k])) for k in sorted(kwargs)
- )
- ]))
-
- kwargs['oauth_signature'] = hmac(
- key, message, sha1
- ).digest().encode('base64')[:-1]
-
- return '%s?%s' % (__url, urlencode(kwargs))
-
-# ------------------------------------------------------------------------------
-# twitter client
-# ------------------------------------------------------------------------------
-
-class TwitterClient(object):
- """Twitter client for the official API."""
-
- def __init__(self, username=None, password=None, oauth=None):
- pass
-
-# ------------------------------------------------------------------------------
-# kore data types
-# ------------------------------------------------------------------------------
-
-class TwitterUser(db.Model):
- """A Twitter User."""
-
-class Tweet(db.Model):
- """A Tweet."""
-
-class TweetBookKeeping(db.Model):
- """Bookkeeping for Tweets."""
-
-# ------------------------------------------------------------------------------
-# self runner -- app engine cached main() function
-# ------------------------------------------------------------------------------
-
-def main():
- import source.main
- run_wsgi_app(Application)
-
-# ------------------------------------------------------------------------------
-# run in standalone mode
-# ------------------------------------------------------------------------------
-
-if __name__ == '__main__':
- main()
View
0 app/source/__init__.py
No changes.
View
2,138 app/third_party/demjson.py
@@ -1,2138 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-#
-r""" A JSON data encoder and decoder.
-
- This Python module implements the JSON (http://json.org/) data
- encoding format; a subset of ECMAScript (aka JavaScript) for encoding
- primitive data types (numbers, strings, booleans, lists, and
- associative arrays) in a language-neutral simple text-based syntax.
-
- It can encode or decode between JSON formatted strings and native
- Python data types. Normally you would use the encode() and decode()
- functions defined by this module, but if you want more control over
- the processing you can use the JSON class.
-
- This implementation tries to be as completely cormforming to all
- intricacies of the standards as possible. It can operate in strict
- mode (which only allows JSON-compliant syntax) or a non-strict mode
- (which allows much more of the whole ECMAScript permitted syntax).
- This includes complete support for Unicode strings (including
- surrogate-pairs for non-BMP characters), and all number formats
- including negative zero and IEEE 754 non-numbers such a NaN or
- Infinity.
-
- The JSON/ECMAScript to Python type mappings are:
- ---JSON--- ---Python---
- null None
- undefined undefined (note 1)
- Boolean (true,false) bool (True or False)
- Integer int or long (note 2)
- Float float
- String str or unicode ( "..." or u"..." )
- Array [a, ...] list ( [...] )
- Object {a:b, ...} dict ( {...} )
-
- -- Note 1. an 'undefined' object is declared in this module which
- represents the native Python value for this type when in
- non-strict mode.
-
- -- Note 2. some ECMAScript integers may be up-converted to Python
- floats, such as 1e+40. Also integer -0 is converted to
- float -0, so as to preserve the sign (which ECMAScript requires).
-
- In addition, when operating in non-strict mode, several IEEE 754
- non-numbers are also handled, and are mapped to specific Python
- objects declared in this module:
-
- NaN (not a number) nan (float('nan'))
- Infinity, +Infinity inf (float('inf'))
- -Infinity neginf (float('-inf'))
-
- When encoding Python objects into JSON, you may use types other than
- native lists or dictionaries, as long as they support the minimal
- interfaces required of all sequences or mappings. This means you can
- use generators and iterators, tuples, UserDict subclasses, etc.
-
- To make it easier to produce JSON encoded representations of user
- defined classes, if the object has a method named json_equivalent(),
- then it will call that method and attempt to encode the object
- returned from it instead. It will do this recursively as needed and
- before any attempt to encode the object using it's default
- strategies. Note that any json_equivalent() method should return
- "equivalent" Python objects to be encoded, not an already-encoded
- JSON-formatted string. There is no such aid provided to decode
- JSON back into user-defined classes as that would dramatically
- complicate the interface.
-
- When decoding strings with this module it may operate in either
- strict or non-strict mode. The strict mode only allows syntax which
- is conforming to RFC 4627 (JSON), while the non-strict allows much
- more of the permissible ECMAScript syntax.
-
- The following are permitted when processing in NON-STRICT mode:
-
- * Unicode format control characters are allowed anywhere in the input.
- * All Unicode line terminator characters are recognized.
- * All Unicode white space characters are recognized.
- * The 'undefined' keyword is recognized.
- * Hexadecimal number literals are recognized (e.g., 0xA6, 0177).
- * String literals may use either single or double quote marks.
- * Strings may contain \x (hexadecimal) escape sequences, as well as the
- \v and \0 escape sequences.
- * Lists may have omitted (elided) elements, e.g., [,,,,,], with
- missing elements interpreted as 'undefined' values.
- * Object properties (dictionary keys) can be of any of the
- types: string literals, numbers, or identifiers (the later of
- which are treated as if they are string literals)---as permitted
- by ECMAScript. JSON only permits strings literals as keys.
-
- Concerning non-strict and non-ECMAScript allowances:
-
- * Octal numbers: If you allow the 'octal_numbers' behavior (which
- is never enabled by default), then you can use octal integers
- and octal character escape sequences (per the ECMAScript
- standard Annex B.1.2). This behavior is allowed, if enabled,
- because it was valid JavaScript at one time.
-
- * Multi-line string literals: Strings which are more than one
- line long (contain embedded raw newline characters) are never
- permitted. This is neither valid JSON nor ECMAScript. Some other
- JSON implementations may allow this, but this module considers
- that behavior to be a mistake.
-
- References:
- * JSON (JavaScript Object Notation)
- <http://json.org/>
- * RFC 4627. The application/json Media Type for JavaScript Object Notation (JSON)
- <http://www.ietf.org/rfc/rfc4627.txt>
- * ECMA-262 3rd edition (1999)
- <http://www.ecma-international.org/publications/files/ecma-st/ECMA-262.pdf>
- * IEEE 754-1985: Standard for Binary Floating-Point Arithmetic.
- <http://www.cs.berkeley.edu/~ejr/Projects/ieee754/>
-
-"""
-
-__author__ = "Deron Meranda <http://deron.meranda.us/>"
-__date__ = "2008-12-17"
-__version__ = "1.4"
-__credits__ = """Copyright (c) 2006-2008 Deron E. Meranda <http://deron.meranda.us/>
-Licensed under GNU LGPL 3.0 (GNU Lesser General Public License) or
-later. See LICENSE.txt included with this software.
-
-This program is free software: you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as
-published by the Free Software Foundation, either version 3 of the
-License, or (at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>
-or <http://www.fsf.org/licensing/>.
-
-"""
-
-# ------------------------------
-# useful global constants
-
-content_type = 'application/json'
-file_ext = 'json'
-hexdigits = '0123456789ABCDEFabcdef'
-octaldigits = '01234567'
-
-# ----------------------------------------------------------------------
-# Decimal and float types.
-#
-# If a JSON number can not be stored in a Python float without loosing
-# precision and the Python has the decimal type, then we will try to
-# use decimal instead of float. To make this determination we need to
-# know the limits of the float type, but Python doesn't have an easy
-# way to tell what the largest floating-point number it supports. So,
-# we detemine the precision and scale of the float type by testing it.
-
-try:
- # decimal module was introduced in Python 2.4
- import decimal
-except ImportError:
- decimal = None
-
-def determine_float_precision():
- """Returns a tuple (significant_digits, max_exponent) for the float type.
- """
- import math
- # Just count the digits in pi. The last two decimal digits
- # may only be partial digits, so discount for them.
- whole, frac = repr(math.pi).split('.')
- sigdigits = len(whole) + len(frac) - 2
-
- # This is a simple binary search. We find the largest exponent
- # that the float() type can handle without going infinite or
- # raising errors.
- maxexp = None
- minv = 0; maxv = 1000
- while True:
- if minv+1 == maxv:
- maxexp = minv - 1
- break
- elif maxv < minv:
- maxexp = None
- break
- m = (minv + maxv) // 2
- try:
- f = repr(float( '1e+%d' % m ))
- except ValueError:
- f = None
- else:
- if not f or f[0] < '0' or f[0] > '9':
- f = None
- if not f:
- # infinite
- maxv = m
- else:
- minv = m
- return sigdigits, maxexp
-
-float_sigdigits, float_maxexp = determine_float_precision()
-
-# ----------------------------------------------------------------------
-# The undefined value.
-#
-# ECMAScript has an undefined value (similar to yet distinct from null).
-# Neither Python or strict JSON have support undefined, but to allow
-# JavaScript behavior we must simulate it.
-
-class _undefined_class(object):
- """Represents the ECMAScript 'undefined' value."""
- __slots__ = []
- def __repr__(self):
- return self.__module__ + '.undefined'
- def __str__(self):
- return 'undefined'
- def __nonzero__(self):
- return False
-undefined = _undefined_class()
-del _undefined_class
-
-
-# ----------------------------------------------------------------------
-# Non-Numbers: NaN, Infinity, -Infinity
-#
-# ECMAScript has official support for non-number floats, although
-# strict JSON does not. Python doesn't either. So to support the
-# full JavaScript behavior we must try to add them into Python, which
-# is unfortunately a bit of black magic. If our python implementation
-# happens to be built on top of IEEE 754 we can probably trick python
-# into using real floats. Otherwise we must simulate it with classes.
-
-def _nonnumber_float_constants():
- """Try to return the Nan, Infinity, and -Infinity float values.
-
- This is unnecessarily complex because there is no standard
- platform- independent way to do this in Python as the language
- (opposed to some implementation of it) doesn't discuss
- non-numbers. We try various strategies from the best to the
- worst.
-
- If this Python interpreter uses the IEEE 754 floating point
- standard then the returned values will probably be real instances
- of the 'float' type. Otherwise a custom class object is returned
- which will attempt to simulate the correct behavior as much as
- possible.
-
- """
- try:
- # First, try (mostly portable) float constructor. Works under
- # Linux x86 (gcc) and some Unices.
- nan = float('nan')
- inf = float('inf')
- neginf = float('-inf')
- except ValueError:
- try:
- # Try the AIX (PowerPC) float constructors
- nan = float('NaNQ')
- inf = float('INF')
- neginf = float('-INF')
- except ValueError:
- try:
- # Next, try binary unpacking. Should work under
- # platforms using IEEE 754 floating point.
- import struct, sys
- xnan = '7ff8000000000000'.decode('hex') # Quiet NaN
- xinf = '7ff0000000000000'.decode('hex')
- xcheck = 'bdc145651592979d'.decode('hex') # -3.14159e-11
- # Could use float.__getformat__, but it is a new python feature,
- # so we use sys.byteorder.
- if sys.byteorder == 'big':
- nan = struct.unpack('d', xnan)[0]
- inf = struct.unpack('d', xinf)[0]
- check = struct.unpack('d', xcheck)[0]
- else:
- nan = struct.unpack('d', xnan[::-1])[0]
- inf = struct.unpack('d', xinf[::-1])[0]
- check = struct.unpack('d', xcheck[::-1])[0]
- neginf = - inf
- if check != -3.14159e-11:
- raise ValueError('Unpacking raw IEEE 754 floats does not work')
- except (ValueError, TypeError):
- # Punt, make some fake classes to simulate. These are
- # not perfect though. For instance nan * 1.0 == nan,
- # as expected, but 1.0 * nan == 0.0, which is wrong.
- class nan(float):
- """An approximation of the NaN (not a number) floating point number."""
- def __repr__(self): return 'nan'
- def __str__(self): return 'nan'
- def __add__(self,x): return self
- def __radd__(self,x): return self
- def __sub__(self,x): return self
- def __rsub__(self,x): return self
- def __mul__(self,x): return self
- def __rmul__(self,x): return self
- def __div__(self,x): return self
- def __rdiv__(self,x): return self
- def __divmod__(self,x): return (self,self)
- def __rdivmod__(self,x): return (self,self)
- def __mod__(self,x): return self
- def __rmod__(self,x): return self
- def __pow__(self,exp): return self
- def __rpow__(self,exp): return self
- def __neg__(self): return self
- def __pos__(self): return self
- def __abs__(self): return self
- def __lt__(self,x): return False
- def __le__(self,x): return False
- def __eq__(self,x): return False
- def __neq__(self,x): return True
- def __ge__(self,x): return False
- def __gt__(self,x): return False
- def __complex__(self,*a): raise NotImplementedError('NaN can not be converted to a complex')
- if decimal:
- nan = decimal.Decimal('NaN')
- else:
- nan = nan()
- class inf(float):
- """An approximation of the +Infinity floating point number."""
- def __repr__(self): return 'inf'
- def __str__(self): return 'inf'
- def __add__(self,x): return self
- def __radd__(self,x): return self
- def __sub__(self,x): return self
- def __rsub__(self,x): return self
- def __mul__(self,x):
- if x is neginf or x < 0:
- return neginf
- elif x == 0:
- return nan
- else:
- return self
- def __rmul__(self,x): return self.__mul__(x)
- def __div__(self,x):
- if x == 0:
- raise ZeroDivisionError('float division')
- elif x < 0:
- return neginf
- else:
- return self
- def __rdiv__(self,x):
- if x is inf or x is neginf or x is nan:
- return nan
- return 0.0
- def __divmod__(self,x):
- if x == 0:
- raise ZeroDivisionError('float divmod()')
- elif x < 0:
- return (nan,nan)
- else:
- return (self,self)
- def __rdivmod__(self,x):
- if x is inf or x is neginf or x is nan:
- return (nan, nan)
- return (0.0, x)
- def __mod__(self,x):
- if x == 0:
- raise ZeroDivisionError('float modulo')
- else:
- return nan
- def __rmod__(self,x):
- if x is inf or x is neginf or x is nan:
- return nan
- return x
- def __pow__(self, exp):
- if exp == 0:
- return 1.0
- else:
- return self
- def __rpow__(self, x):
- if -1 < x < 1: return 0.0
- elif x == 1.0: return 1.0
- elif x is nan or x is neginf or x < 0:
- return nan
- else:
- return self
- def __neg__(self): return neginf
- def __pos__(self): return self
- def __abs__(self): return self
- def __lt__(self,x): return False
- def __le__(self,x):
- if x is self:
- return True
- else:
- return False
- def __eq__(self,x):
- if x is self:
- return True
- else:
- return False
- def __neq__(self,x):
- if x is self:
- return False
- else:
- return True
- def __ge__(self,x): return True
- def __gt__(self,x): return True
- def __complex__(self,*a): raise NotImplementedError('Infinity can not be converted to a complex')
- if decimal:
- inf = decimal.Decimal('Infinity')
- else:
- inf = inf()
- class neginf(float):
- """An approximation of the -Infinity floating point number."""
- def __repr__(self): return '-inf'
- def __str__(self): return '-inf'
- def __add__(self,x): return self
- def __radd__(self,x): return self
- def __sub__(self,x): return self
- def __rsub__(self,x): return self
- def __mul__(self,x):
- if x is self or x < 0:
- return inf
- elif x == 0:
- return nan
- else:
- return self
- def __rmul__(self,x): return self.__mul__(self)
- def __div__(self,x):
- if x == 0:
- raise ZeroDivisionError('float division')
- elif x < 0:
- return inf
- else:
- return self
- def __rdiv__(self,x):
- if x is inf or x is neginf or x is nan:
- return nan
- return -0.0
- def __divmod__(self,x):
- if x == 0:
- raise ZeroDivisionError('float divmod()')
- elif x < 0:
- return (nan,nan)
- else:
- return (self,self)
- def __rdivmod__(self,x):
- if x is inf or x is neginf or x is nan:
- return (nan, nan)
- return (-0.0, x)
- def __mod__(self,x):
- if x == 0:
- raise ZeroDivisionError('float modulo')
- else:
- return nan
- def __rmod__(self,x):
- if x is inf or x is neginf or x is nan:
- return nan
- return x
- def __pow__(self,exp):
- if exp == 0:
- return 1.0
- else:
- return self
- def __rpow__(self, x):
- if x is nan or x is inf or x is inf:
- return nan
- return 0.0
- def __neg__(self): return inf
- def __pos__(self): return self
- def __abs__(self): return inf
- def __lt__(self,x): return True
- def __le__(self,x): return True
- def __eq__(self,x):
- if x is self:
- return True
- else:
- return False
- def __neq__(self,x):
- if x is self:
- return False
- else:
- return True
- def __ge__(self,x):
- if x is self:
- return True
- else:
- return False
- def __gt__(self,x): return False
- def __complex__(self,*a): raise NotImplementedError('-Infinity can not be converted to a complex')
- if decimal:
- neginf = decimal.Decimal('-Infinity')
- else:
- neginf = neginf(0)
- return nan, inf, neginf
-
-nan, inf, neginf = _nonnumber_float_constants()
-del _nonnumber_float_constants
-
-
-# ----------------------------------------------------------------------
-# String processing helpers
-
-unsafe_string_chars = '"\\' + ''.join([chr(i) for i in range(0x20)])
-def skipstringsafe( s, start=0, end=None ):
- i = start
- #if end is None:
- # end = len(s)
- while i < end and s[i] not in unsafe_string_chars:
- #c = s[i]
- #if c in unsafe_string_chars:
- # break
- i += 1
- return i
-def skipstringsafe_slow( s, start=0, end=None ):
- i = start
- if end is None:
- end = len(s)
- while i < end:
- c = s[i]
- if c == '"' or c == '\\' or ord(c) <= 0x1f:
- break
- i += 1
- return i
-
-def extend_list_with_sep( orig_seq, extension_seq, sepchar='' ):
- if not sepchar:
- orig_seq.extend( extension_seq )
- else:
- for i, x in enumerate(extension_seq):
- if i > 0:
- orig_seq.append( sepchar )
- orig_seq.append( x )
-
-def extend_and_flatten_list_with_sep( orig_seq, extension_seq, separator='' ):
- for i, part in enumerate(extension_seq):
- if i > 0 and separator:
- orig_seq.append( separator )
- orig_seq.extend( part )
-
-
-# ----------------------------------------------------------------------
-# Unicode helpers
-#
-# JSON requires that all JSON implementations must support the UTF-32
-# encoding (as well as UTF-8 and UTF-16). But earlier versions of
-# Python did not provide a UTF-32 codec. So we must implement UTF-32
-# ourselves in case we need it.
-
-def utf32le_encode( obj, errors='strict' ):
- """Encodes a Unicode string into a UTF-32LE encoded byte string."""
- import struct
- try:
- import cStringIO as sio
- except ImportError:
- import StringIO as sio
- f = sio.StringIO()
- write = f.write
- pack = struct.pack
- for c in obj:
- n = ord(c)
- if 0xD800 <= n <= 0xDFFF: # surrogate codepoints are prohibited by UTF-32
- if errors == 'ignore':
- continue
- elif errors == 'replace':
- n = ord('?')
- else:
- cname = 'U+%04X'%n
- raise UnicodeError('UTF-32 can not encode surrogate characters',cname)
- write( pack('<L', n) )
- return f.getvalue()
-
-
-def utf32be_encode( obj, errors='strict' ):
- """Encodes a Unicode string into a UTF-32BE encoded byte string."""
- import struct
- try:
- import cStringIO as sio
- except ImportError:
- import StringIO as sio
- f = sio.StringIO()
- write = f.write
- pack = struct.pack
- for c in obj:
- n = ord(c)
- if 0xD800 <= n <= 0xDFFF: # surrogate codepoints are prohibited by UTF-32
- if errors == 'ignore':
- continue
- elif errors == 'replace':
- n = ord('?')
- else:
- cname = 'U+%04X'%n
- raise UnicodeError('UTF-32 can not encode surrogate characters',cname)
- write( pack('>L', n) )
- return f.getvalue()
-
-
-def utf32le_decode( obj, errors='strict' ):
- """Decodes a UTF-32LE byte string into a Unicode string."""
- if len(obj) % 4 != 0:
- raise UnicodeError('UTF-32 decode error, data length not a multiple of 4 bytes')
- import struct
- unpack = struct.unpack
- chars = []
- i = 0
- for i in range(0, len(obj), 4):
- seq = obj[i:i+4]
- n = unpack('<L',seq)[0]
- chars.append( unichr(n) )
- return u''.join( chars )
-
-
-def utf32be_decode( obj, errors='strict' ):
- """Decodes a UTF-32BE byte string into a Unicode string."""
- if len(obj) % 4 != 0:
- raise UnicodeError('UTF-32 decode error, data length not a multiple of 4 bytes')
- import struct
- unpack = struct.unpack
- chars = []
- i = 0
- for i in range(0, len(obj), 4):
- seq = obj[i:i+4]
- n = unpack('>L',seq)[0]
- chars.append( unichr(n) )
- return u''.join( chars )
-
-
-def auto_unicode_decode( s ):
- """Takes a string and tries to convert it to a Unicode string.
-
- This will return a Python unicode string type corresponding to the
- input string (either str or unicode). The character encoding is
- guessed by looking for either a Unicode BOM prefix, or by the
- rules specified by RFC 4627. When in doubt it is assumed the
- input is encoded in UTF-8 (the default for JSON).
-
- """
- if isinstance(s, unicode):
- return s
- if len(s) < 4:
- return s.decode('utf8') # not enough bytes, assume default of utf-8
- # Look for BOM marker
- import codecs
- bom2 = s[:2]
- bom4 = s[:4]
- a, b, c, d = map(ord, s[:4]) # values of first four bytes
- if bom4 == codecs.BOM_UTF32_LE:
- encoding = 'utf-32le'
- s = s[4:]
- elif bom4 == codecs.BOM_UTF32_BE:
- encoding = 'utf-32be'
- s = s[4:]
- elif bom2 == codecs.BOM_UTF16_LE:
- encoding = 'utf-16le'
- s = s[2:]
- elif bom2 == codecs.BOM_UTF16_BE:
- encoding = 'utf-16be'
- s = s[2:]
- # No BOM, so autodetect encoding used by looking at first four bytes
- # according to RFC 4627 section 3.
- elif a==0 and b==0 and c==0 and d!=0: # UTF-32BE
- encoding = 'utf-32be'
- elif a==0 and b!=0 and c==0 and d!=0: # UTF-16BE
- encoding = 'utf-16be'
- elif a!=0 and b==0 and c==0 and d==0: # UTF-32LE
- encoding = 'utf-32le'
- elif a!=0 and b==0 and c!=0 and d==0: # UTF-16LE
- encoding = 'utf-16le'
- else: #if a!=0 and b!=0 and c!=0 and d!=0: # UTF-8
- # JSON spec says default is UTF-8, so always guess it
- # if we can't guess otherwise
- encoding = 'utf8'
- # Make sure the encoding is supported by Python
- try:
- cdk = codecs.lookup(encoding)
- except LookupError:
- if encoding.startswith('utf-32') \
- or encoding.startswith('ucs4') \
- or encoding.startswith('ucs-4'):
- # Python doesn't natively have a UTF-32 codec, but JSON
- # requires that it be supported. So we must decode these
- # manually.
- if encoding.endswith('le'):
- unis = utf32le_decode(s)
- else:
- unis = utf32be_decode(s)
- else:
- raise JSONDecodeError('this python has no codec for this character encoding',encoding)
- else:
- # Convert to unicode using a standard codec
- unis = s.decode(encoding)
- return unis
-
-
-def surrogate_pair_as_unicode( c1, c2 ):
- """Takes a pair of unicode surrogates and returns the equivalent unicode character.
-
- The input pair must be a surrogate pair, with c1 in the range
- U+D800 to U+DBFF and c2 in the range U+DC00 to U+DFFF.
-
- """
- n1, n2 = ord(c1), ord(c2)
- if n1 < 0xD800 or n1 > 0xDBFF or n2 < 0xDC00 or n2 > 0xDFFF:
- raise JSONDecodeError('illegal Unicode surrogate pair',(c1,c2))
- a = n1 - 0xD800
- b = n2 - 0xDC00
- v = (a << 10) | b
- v += 0x10000
- return unichr(v)
-
-
-def unicode_as_surrogate_pair( c ):
- """Takes a single unicode character and returns a sequence of surrogate pairs.
-
- The output of this function is a tuple consisting of one or two unicode
- characters, such that if the input character is outside the BMP range
- then the output is a two-character surrogate pair representing that character.
-
- If the input character is inside the BMP then the output tuple will have
- just a single character...the same one.
-
- """
- n = ord(c)
- if n < 0x10000:
- return (unichr(n),) # in BMP, surrogate pair not required
- v = n - 0x10000
- vh = (v >> 10) & 0x3ff # highest 10 bits
- vl = v & 0x3ff # lowest 10 bits
- w1 = 0xD800 | vh
- w2 = 0xDC00 | vl
- return (unichr(w1), unichr(w2))
-
-
-# ----------------------------------------------------------------------
-# Type identification
-
-def isnumbertype( obj ):
- """Is the object of a Python number type (excluding complex)?"""
- return isinstance(obj, (int,long,float)) \
- and not isinstance(obj, bool) \
- or obj is nan or obj is inf or obj is neginf
-
-
-def isstringtype( obj ):
- """Is the object of a Python string type?"""
- if isinstance(obj, basestring):
- return True
- # Must also check for some other pseudo-string types
- import types, UserString
- return isinstance(obj, types.StringTypes) \
- or isinstance(obj, UserString.UserString) \
- or isinstance(obj, UserString.MutableString)
-
-
-# ----------------------------------------------------------------------
-# Numeric helpers
-
-def decode_hex( hexstring ):
- """Decodes a hexadecimal string into it's integer value."""
- # We don't use the builtin 'hex' codec in python since it can
- # not handle odd numbers of digits, nor raise the same type
- # of exceptions we want to.
- n = 0
- for c in hexstring:
- if '0' <= c <= '9':
- d = ord(c) - ord('0')
- elif 'a' <= c <= 'f':
- d = ord(c) - ord('a') + 10
- elif 'A' <= c <= 'F':
- d = ord(c) - ord('A') + 10
- else:
- raise JSONDecodeError('not a hexadecimal number',hexstring)
- # Could use ((n << 4 ) | d), but python 2.3 issues a FutureWarning.
- n = (n * 16) + d
- return n
-
-
-def decode_octal( octalstring ):
- """Decodes an octal string into it's integer value."""
- n = 0
- for c in octalstring:
- if '0' <= c <= '7':
- d = ord(c) - ord('0')
- else:
- raise JSONDecodeError('not an octal number',octalstring)
- # Could use ((n << 3 ) | d), but python 2.3 issues a FutureWarning.
- n = (n * 8) + d
- return n
-
-
-# ----------------------------------------------------------------------
-# Exception classes.
-
-class JSONError(ValueError):
- """Our base class for all JSON-related errors.
-
- """
- def pretty_description(self):
- err = self.args[0]
- if len(self.args) > 1:
- err += ': '
- for anum, a in enumerate(self.args[1:]):
- if anum > 1:
- err += ', '
- astr = repr(a)
- if len(astr) > 20:
- astr = astr[:20] + '...'
- err += astr
- return err
-
-class JSONDecodeError(JSONError):
- """An exception class raised when a JSON decoding error (syntax error) occurs."""
-
-
-class JSONEncodeError(JSONError):
- """An exception class raised when a python object can not be encoded as a JSON string."""
-
-
-#----------------------------------------------------------------------
-# The main JSON encoder/decoder class.
-
-class JSON(object):
- """An encoder/decoder for JSON data streams.
-
- Usually you will call the encode() or decode() methods. The other
- methods are for lower-level processing.
-
- Whether the JSON parser runs in strict mode (which enforces exact
- compliance with the JSON spec) or the more forgiving non-string mode
- can be affected by setting the 'strict' argument in the object's
- initialization; or by assigning True or False to the 'strict'
- property of the object.
-
- You can also adjust a finer-grained control over strictness by
- allowing or preventing specific behaviors. You can get a list of
- all the available behaviors by accessing the 'behaviors' property.
- Likewise the allowed_behaviors and prevented_behaviors list which
- behaviors will be allowed and which will not. Call the allow()
- or prevent() methods to adjust these.
-
- """
- _escapes_json = { # character escapes in JSON
- '"': '"',
- '/': '/',
- '\\': '\\',
- 'b': '\b',
- 'f': '\f',
- 'n': '\n',
- 'r': '\r',
- 't': '\t',
- }
-
- _escapes_js = { # character escapes in Javascript
- '"': '"',
- '\'': '\'',
- '\\': '\\',
- 'b': '\b',
- 'f': '\f',
- 'n': '\n',
- 'r': '\r',
- 't': '\t',
- 'v': '\v',
- '0': '\x00'
- }
-
- # Following is a reverse mapping of escape characters, used when we
- # output JSON. Only those escapes which are always safe (e.g., in JSON)
- # are here. It won't hurt if we leave questionable ones out.
- _rev_escapes = {'\n': '\\n',
- '\t': '\\t',
- '\b': '\\b',
- '\r': '\\r',
- '\f': '\\f',
- '"': '\\"',
- '\\': '\\\\'}
-
- def __init__(self, strict=False, compactly=True, escape_unicode=False):
- """Creates a JSON encoder/decoder object.
-
- If 'strict' is set to True, then only strictly-conforming JSON
- output will be produced. Note that this means that some types
- of values may not be convertable and will result in a
- JSONEncodeError exception.
-
- If 'compactly' is set to True, then the resulting string will
- have all extraneous white space removed; if False then the
- string will be "pretty printed" with whitespace and indentation
- added to make it more readable.
-
- If 'escape_unicode' is set to True, then all non-ASCII characters
- will be represented as a unicode escape sequence; if False then
- the actual real unicode character will be inserted if possible.
-
- The 'escape_unicode' can also be a function, which when called
- with a single argument of a unicode character will return True
- if the character should be escaped or False if it should not.
-
- If you wish to extend the encoding to ba able to handle
- additional types, you should subclass this class and override
- the encode_default() method.
-
- """
- import sys
- self._set_strictness(strict)
- self._encode_compactly = compactly
- try:
- # see if we were passed a predicate function
- b = escape_unicode(u'A')
- self._encode_unicode_as_escapes = escape_unicode
- except (ValueError, NameError, TypeError):
- # Just set to True or False. We could use lambda x:True
- # to make it more consistent (always a function), but it
- # will be too slow, so we'll make explicit tests later.
- self._encode_unicode_as_escapes = bool(escape_unicode)
- self._sort_dictionary_keys = True
-
- # The following is a boolean map of the first 256 characters
- # which will quickly tell us which of those characters never
- # need to be escaped.
-
- self._asciiencodable = [32 <= c < 128 and not self._rev_escapes.has_key(chr(c))
- for c in range(0,255)]
-
- def _set_strictness(self, strict):
- """Changes the strictness behavior.
-
- Pass True to be very strict about JSON syntax, or False to be looser.
- """
- self._allow_any_type_at_start = not strict
- self._allow_all_numeric_signs = not strict
- self._allow_comments = not strict
- self._allow_control_char_in_string = not strict
- self._allow_hex_numbers = not strict
- self._allow_initial_decimal_point = not strict
- self._allow_js_string_escapes = not strict
- self._allow_non_numbers = not strict
- self._allow_nonescape_characters = not strict # "\z" -> "z"
- self._allow_nonstring_keys = not strict
- self._allow_omitted_array_elements = not strict
- self._allow_single_quoted_strings = not strict
- self._allow_trailing_comma_in_literal = not strict
- self._allow_undefined_values = not strict
- self._allow_unicode_format_control_chars = not strict
- self._allow_unicode_whitespace = not strict
- # Always disable this by default
- self._allow_octal_numbers = False
-
- def allow(self, behavior):
- """Allow the specified behavior (turn off a strictness check).
-
- The list of all possible behaviors is available in the behaviors property.
- You can see which behaviors are currently allowed by accessing the
- allowed_behaviors property.
-
- """
- p = '_allow_' + behavior
- if hasattr(self, p):
- setattr(self, p, True)
- else:
- raise AttributeError('Behavior is not known',behavior)
-
- def prevent(self, behavior):
- """Prevent the specified behavior (turn on a strictness check).
-
- The list of all possible behaviors is available in the behaviors property.
- You can see which behaviors are currently prevented by accessing the
- prevented_behaviors property.
-
- """
- p = '_allow_' + behavior
- if hasattr(self, p):
- setattr(self, p, False)
- else:
- raise AttributeError('Behavior is not known',behavior)
-
- def _get_behaviors(self):
- return sorted([ n[len('_allow_'):] for n in self.__dict__ \
- if n.startswith('_allow_')])
- behaviors = property(_get_behaviors,
- doc='List of known behaviors that can be passed to allow() or prevent() methods')
-
- def _get_allowed_behaviors(self):
- return sorted([ n[len('_allow_'):] for n in self.__dict__ \
- if n.startswith('_allow_') and getattr(self,n)])
- allowed_behaviors = property(_get_allowed_behaviors,
- doc='List of known behaviors that are currently allowed')
-
- def _get_prevented_behaviors(self):
- return sorted([ n[len('_allow_'):] for n in self.__dict__ \
- if n.startswith('_allow_') and not getattr(self,n)])
- prevented_behaviors = property(_get_prevented_behaviors,
- doc='List of known behaviors that are currently prevented')
-
- def _is_strict(self):
- return not self.allowed_behaviors
- strict = property(_is_strict, _set_strictness,
- doc='True if adherence to RFC 4627 syntax is strict, or False is more generous ECMAScript syntax is permitted')
-
-
- def isws(self, c):
- """Determines if the given character is considered as white space.
-
- Note that Javscript is much more permissive on what it considers
- to be whitespace than does JSON.
-
- Ref. ECMAScript section 7.2
-
- """
- if not self._allow_unicode_whitespace:
- return c in ' \t\n\r'
- else:
- if not isinstance(c,unicode):
- c = unicode(c)
- if c in u' \t\n\r\f\v':
- return True
- import unicodedata
- return unicodedata.category(c) == 'Zs'
-
- def islineterm(self, c):
- """Determines if the given character is considered a line terminator.
-
- Ref. ECMAScript section 7.3
-
- """
- if c == '\r' or c == '\n':
- return True
- if c == u'\u2028' or c == u'\u2029': # unicodedata.category(c) in ['Zl', 'Zp']
- return True
- return False
-
- def strip_format_control_chars(self, txt):
- """Filters out all Unicode format control characters from the string.
-
- ECMAScript permits any Unicode "format control characters" to
- appear at any place in the source code. They are to be
- ignored as if they are not there before any other lexical
- tokenization occurs. Note that JSON does not allow them.
-
- Ref. ECMAScript section 7.1.
-
- """
- import unicodedata
- txt2 = filter( lambda c: unicodedata.category(unicode(c)) != 'Cf',
- txt )
- return txt2
-
-
- def decode_null(self, s, i=0):
- """Intermediate-level decoder for ECMAScript 'null' keyword.
-
- Takes a string and a starting index, and returns a Python
- None object and the index of the next unparsed character.
-
- """
- if i < len(s) and s[i:i+4] == 'null':
- return None, i+4
- raise JSONDecodeError('literal is not the JSON "null" keyword', s)
-
- def encode_undefined(self):
- """Produces the ECMAScript 'undefined' keyword."""
- return 'undefined'
-
- def encode_null(self):
- """Produces the JSON 'null' keyword."""
- return 'null'
-
- def decode_boolean(self, s, i=0):
- """Intermediate-level decode for JSON boolean literals.
-
- Takes a string and a starting index, and returns a Python bool
- (True or False) and the index of the next unparsed character.
-
- """
- if s[i:i+4] == 'true':
- return True, i+4
- elif s[i:i+5] == 'false':
- return False, i+5
- raise JSONDecodeError('literal value is not a JSON boolean keyword',s)
-
- def encode_boolean(self, b):
- """Encodes the Python boolean into a JSON Boolean literal."""
- if bool(b):
- return 'true'
- return 'false'
-
- def decode_number(self, s, i=0, imax=None):
- """Intermediate-level decoder for JSON numeric literals.
-
- Takes a string and a starting index, and returns a Python
- suitable numeric type and the index of the next unparsed character.
-
- The returned numeric type can be either of a Python int,
- long, or float. In addition some special non-numbers may
- also be returned such as nan, inf, and neginf (technically
- which are Python floats, but have no numeric value.)
-
- Ref. ECMAScript section 8.5.
-
- """
- if imax is None:
- imax = len(s)
- # Detect initial sign character(s)
- if not self._allow_all_numeric_signs:
- if s[i] == '+' or (s[i] == '-' and i+1 < imax and \
- s[i+1] in '+-'):
- raise JSONDecodeError('numbers in strict JSON may only have a single "-" as a sign prefix',s[i:])
- sign = +1
- j = i # j will point after the sign prefix
- while j < imax and s[j] in '+-':
- if s[j] == '-': sign = sign * -1
- j += 1
- # Check for ECMAScript symbolic non-numbers
- if s[j:j+3] == 'NaN':
- if self._allow_non_numbers:
- return nan, j+3
- else:
- raise JSONDecodeError('NaN literals are not allowed in strict JSON')
- elif s[j:j+8] == 'Infinity':
- if self._allow_non_numbers:
- if sign < 0:
- return neginf, j+8
- else:
- return inf, j+8
- else:
- raise JSONDecodeError('Infinity literals are not allowed in strict JSON')
- elif s[j:j+2] in ('0x','0X'):
- if self._allow_hex_numbers:
- k = j+2
- while k < imax and s[k] in hexdigits:
- k += 1
- n = sign * decode_hex( s[j+2:k] )
- return n, k
- else:
- raise JSONDecodeError('hexadecimal literals are not allowed in strict JSON',s[i:])
- else:
- #