Repository: incubator-wave Updated Branches: refs/heads/master 407074736 -> 78cbf78fb
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/jsonfilter.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/jsonfilter.py b/wave/src/main/java/python/api/simplejson/jsonfilter.py deleted file mode 100644 index 7c0da57..0000000 --- a/wave/src/main/java/python/api/simplejson/jsonfilter.py +++ /dev/null @@ -1,60 +0,0 @@ -# -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# -import simplejson -import cgi - -class JSONFilter(object): - def __init__(self, app, mime_type='text/x-json'): - self.app = app - self.mime_type = mime_type - - def __call__(self, environ, start_response): - # Read JSON POST input to jsonfilter.json if matching mime type - response = {'status': '200 OK', 'headers': []} - def json_start_response(status, headers): - response['status'] = status - response['headers'].extend(headers) - environ['jsonfilter.mime_type'] = self.mime_type - if environ.get('REQUEST_METHOD', '') == 'POST': - if environ.get('CONTENT_TYPE', '') == self.mime_type: - args = [_ for _ in [environ.get('CONTENT_LENGTH')] if _] - data = environ['wsgi.input'].read(*map(int, args)) - environ['jsonfilter.json'] = simplejson.loads(data) - res = simplejson.dumps(self.app(environ, json_start_response)) - jsonp = cgi.parse_qs(environ.get('QUERY_STRING', '')).get('jsonp') - if jsonp: - content_type = 'text/javascript' - res = ''.join(jsonp + ['(', res, ')']) - elif 'Opera' in environ.get('HTTP_USER_AGENT', ''): - # Opera has bunk XMLHttpRequest support for most mime types - content_type = 'text/plain' - else: - content_type = self.mime_type - headers = [ - ('Content-type', content_type), - ('Content-length', len(res)), - ] - headers.extend(response['headers']) - start_response(response['status'], headers) - return [res] - -def factory(app, global_conf, **kw): - return JSONFilter(app, **kw) http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/ordered_dict.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/ordered_dict.py b/wave/src/main/java/python/api/simplejson/ordered_dict.py deleted file mode 100644 index a186e77..0000000 --- a/wave/src/main/java/python/api/simplejson/ordered_dict.py +++ /dev/null @@ -1,139 +0,0 @@ -# -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# -"""Drop-in replacement for collections.OrderedDict by Raymond Hettinger - -http://code.activestate.com/recipes/576693/ - -""" -from UserDict import DictMixin - -# Modified from original to support Python 2.4, see -# http://code.google.com/p/simplejson/issues/detail?id=53 -try: - all -except NameError: - def all(seq): - for elem in seq: - if not elem: - return False - return True - -class OrderedDict(dict, DictMixin): - - def __init__(self, *args, **kwds): - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__end - except AttributeError: - self.clear() - self.update(*args, **kwds) - - def clear(self): - self.__end = end = [] - end += [None, end, end] # sentinel node for doubly linked list - self.__map = {} # key --> [key, prev, next] - dict.clear(self) - - def __setitem__(self, key, value): - if key not in self: - end = self.__end - curr = end[1] - curr[2] = end[1] = self.__map[key] = [key, curr, end] - dict.__setitem__(self, key, value) - - def __delitem__(self, key): - dict.__delitem__(self, key) - key, prev, next = self.__map.pop(key) - prev[2] = next - next[1] = prev - - def __iter__(self): - end = self.__end - curr = end[2] - while curr is not end: - yield curr[0] - curr = curr[2] - - def __reversed__(self): - end = self.__end - curr = end[1] - while curr is not end: - yield curr[0] - curr = curr[1] - - def popitem(self, last=True): - if not self: - raise KeyError('dictionary is empty') - # Modified from original to support Python 2.4, see - # http://code.google.com/p/simplejson/issues/detail?id=53 - if last: - key = reversed(self).next() - else: - key = iter(self).next() - value = self.pop(key) - return key, value - - def __reduce__(self): - items = [[k, self[k]] for k in self] - tmp = self.__map, self.__end - del self.__map, self.__end - inst_dict = vars(self).copy() - self.__map, self.__end = tmp - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def keys(self): - return list(self) - - setdefault = DictMixin.setdefault - update = DictMixin.update - pop = DictMixin.pop - values = DictMixin.values - items = DictMixin.items - iterkeys = DictMixin.iterkeys - itervalues = DictMixin.itervalues - iteritems = DictMixin.iteritems - - def __repr__(self): - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - - def copy(self): - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - if isinstance(other, OrderedDict): - return len(self)==len(other) and \ - all(p==q for p, q in zip(self.items(), other.items())) - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/scanner.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/scanner.py b/wave/src/main/java/python/api/simplejson/scanner.py deleted file mode 100644 index 4e01271..0000000 --- a/wave/src/main/java/python/api/simplejson/scanner.py +++ /dev/null @@ -1,87 +0,0 @@ -# -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# -"""JSON token scanner -""" -import re -try: - from simplejson._speedups import make_scanner as c_make_scanner -except ImportError: - c_make_scanner = None - -__all__ = ['make_scanner'] - -NUMBER_RE = re.compile( - r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?', - (re.VERBOSE | re.MULTILINE | re.DOTALL)) - -def py_make_scanner(context): - parse_object = context.parse_object - parse_array = context.parse_array - parse_string = context.parse_string - match_number = NUMBER_RE.match - encoding = context.encoding - strict = context.strict - parse_float = context.parse_float - parse_int = context.parse_int - parse_constant = context.parse_constant - object_hook = context.object_hook - object_pairs_hook = context.object_pairs_hook - - def _scan_once(string, idx): - try: - nextchar = string[idx] - except IndexError: - raise StopIteration - - if nextchar == '"': - return parse_string(string, idx + 1, encoding, strict) - elif nextchar == '{': - return parse_object((string, idx + 1), encoding, strict, - _scan_once, object_hook, object_pairs_hook) - elif nextchar == '[': - return parse_array((string, idx + 1), _scan_once) - elif nextchar == 'n' and string[idx:idx + 4] == 'null': - return None, idx + 4 - elif nextchar == 't' and string[idx:idx + 4] == 'true': - return True, idx + 4 - elif nextchar == 'f' and string[idx:idx + 5] == 'false': - return False, idx + 5 - - m = match_number(string, idx) - if m is not None: - integer, frac, exp = m.groups() - if frac or exp: - res = parse_float(integer + (frac or '') + (exp or '')) - else: - res = parse_int(integer) - return res, m.end() - elif nextchar == 'N' and string[idx:idx + 3] == 'NaN': - return parse_constant('NaN'), idx + 3 - elif nextchar == 'I' and string[idx:idx + 8] == 'Infinity': - return parse_constant('Infinity'), idx + 8 - elif nextchar == '-' and string[idx:idx + 9] == '-Infinity': - return parse_constant('-Infinity'), idx + 9 - else: - raise StopIteration - - return _scan_once - -make_scanner = c_make_scanner or py_make_scanner http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/tool.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/tool.py b/wave/src/main/java/python/api/simplejson/tool.py deleted file mode 100644 index 646d254..0000000 --- a/wave/src/main/java/python/api/simplejson/tool.py +++ /dev/null @@ -1,57 +0,0 @@ -# -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# -# -r"""Command-line tool to validate and pretty-print JSON - -Usage:: - - $ echo '{"json":"obj"}' | python -m simplejson.tool - { - "json": "obj" - } - $ echo '{ 1.2:3.4}' | python -m simplejson.tool - Expecting property name: line 1 column 2 (char 2) - -""" -import sys -import simplejson as json - -def main(): - if len(sys.argv) == 1: - infile = sys.stdin - outfile = sys.stdout - elif len(sys.argv) == 2: - infile = open(sys.argv[1], 'rb') - outfile = sys.stdout - elif len(sys.argv) == 3: - infile = open(sys.argv[1], 'rb') - outfile = open(sys.argv[2], 'wb') - else: - raise SystemExit(sys.argv[0] + " [infile [outfile]]") - try: - obj = json.load(infile, object_pairs_hook=json.OrderedDict) - except ValueError, e: - raise SystemExit(e) - json.dump(obj, outfile, sort_keys=True, indent=' ') - outfile.write('\n') - - -if __name__ == '__main__': - main() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/testdata.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/testdata.py b/wave/src/main/java/python/api/testdata.py deleted file mode 100644 index fd6b248..0000000 --- a/wave/src/main/java/python/api/testdata.py +++ /dev/null @@ -1,225 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - - -json_string = """{ - "wavelet": { - "creationTime": 1277873815463, - "lastModifiedTime": 1277873843515, - "version": 51, - "participants": [ - "[email protected]", - "[email protected]" - ], - "participantRoles": { - "[email protected]": "FULL", - "[email protected]": "FULL" - }, - "dataDocuments": { - }, - "tags": [ - ], - "creator": "[email protected]", - "rootBlipId": "b+IvD7RCuWB", - "title": "Test", - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "rootThread": { - "id": "", - "location": -1, - "blipIds": [ - "b+IvD7RCuWB", - "b+IvD7RCuWC", - "b+IvD7RCuWE" - ] - } - }, - "blips": { - "b+IvD7RCuWB": { - "annotations": [], - "elements": {}, - "blipId": "b+IvD7RCuWB", - "childBlipIds": [ - "b+IvD7RCuWD" - ], - "contributors": [ - "[email protected]" - ], - "creator": "[email protected]", - "content": "test", - "lastModifiedTime": 1277873815441, - "parentBlipId": null, - "version": 5, - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "replyThreadIds": [ - "b+IvD7RCuWD" - ], - "threadId": "" - }, - "b+IvD7RCuWC": { - "annotations": [ - ], - "elements": { - }, - "blipId": "b+IvD7RCuWC", - "childBlipIds": [ - "b+IvD7RCuWF", - "b+IvD7RCuWG", - "b+IvD7RCuWH" - ], - "contributors": [ - "[email protected]" - ], - "creator": "[email protected]", - "content": "\\ntest", - "lastModifiedTime": 1277873818083, - "parentBlipId": null, - "version": 10, - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "replyThreadIds": [ - "b+IvD7RCuWF" - ], - "threadId": "" - }, - "b+IvD7RCuWH": { - "annotations": [ - ], - "elements": { - }, - "blipId": "b+IvD7RCuWH", - "childBlipIds": [ - ], - "contributors": [ - "[email protected]" - ], - "creator": "[email protected]", - "content": "\\ntest", - "lastModifiedTime": 1277873830724, - "parentBlipId": "b+IvD7RCuWC", - "version": 48, - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "replyThreadIds": [ - ], - "threadId": "b+IvD7RCuWF" - }, - "b+IvD7RCuWF": { - "annotations": [ - ], - "elements": { - }, - "blipId": "b+IvD7RCuWF", - "childBlipIds": [ - ], - "contributors": [ - "[email protected]" - ], - "creator": "[email protected]", - "content": "\\ntest\\n", - "lastModifiedTime": 1277873824775, - "parentBlipId": "b+IvD7RCuWC", - "version": 32, - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "replyThreadIds": [ - ], - "threadId": "b+IvD7RCuWF" - }, - "b+IvD7RCuWG": { - "annotations": [ - ], - "elements": { - }, - "blipId": "b+IvD7RCuWG", - "childBlipIds": [ - ], - "contributors": [ - "[email protected]" - ], - "creator": "[email protected]", - "content": "\\ntest\\n", - "lastModifiedTime": 1277873828985, - "parentBlipId": "b+IvD7RCuWC", - "version": 41, - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "replyThreadIds": [ - ], - "threadId": "b+IvD7RCuWF" - }, - "b+IvD7RCuWD": { - "annotations": [], - "elements": { }, - "blipId": "b+IvD7RCuWD", - "childBlipIds": [ ], - "contributors": [ - "[email protected]" - ], - "creator": "[email protected]", - "content": "\\ntest", - "lastModifiedTime": 1277873819390, - "parentBlipId": "b+IvD7RCuWB", - "version": 18, - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "replyThreadIds": [ - ], - "threadId": "b+IvD7RCuWD" - }, - "b+IvD7RCuWE": { - "annotations": [], - "elements": {}, - "blipId": "b+IvD7RCuWE", - "childBlipIds": [ - ], - "contributors": [ - "[email protected]" - ], - "creator": "[email protected]", - "content": "\\nTest", - "lastModifiedTime": 1277873822476, - "parentBlipId": null, - "version": 26, - "waveId": "wavesandbox.com!w+IvD7RCuWA", - "waveletId": "wavesandbox.com!conv+root", - "replyThreadIds": [ - ], - "threadId": "" - } - }, - "threads": { - "b+IvD7RCuWF": { - "id": "b+IvD7RCuWF", - "location": -1, - "blipIds": [ - "b+IvD7RCuWF", - "b+IvD7RCuWG", - "b+IvD7RCuWH" - ] - }, - "b+IvD7RCuWD": { - "id": "b+IvD7RCuWD", - "location": -1, - "blipIds": [ - "b+IvD7RCuWD" - ] - } - }, - "robotAddress": "[email protected]" -}""" http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/util.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/util.py b/wave/src/main/java/python/api/util.py deleted file mode 100644 index ab7bc2c..0000000 --- a/wave/src/main/java/python/api/util.py +++ /dev/null @@ -1,198 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Utility library containing various helpers used by the API.""" - -import re - -CUSTOM_SERIALIZE_METHOD_NAME = 'serialize' - -MARKUP_RE = re.compile(r'<([^>]*?)>') -RESERVED_PROXY_FOR_CHARS_RE = re.compile(ur'[\s\u0000-\u001F@,:<>\u007F]') - -def force_unicode(object): - """ Return the Unicode string version of object, with UTF-8 encoding. """ - if isinstance(object, unicode): - return object - return unicode(str(object), 'utf-8') - -def parse_markup(markup): - """Parses a bit of markup into robot compatible text. - - For now this is a rough approximation. - """ - def replace_tag(group): - if not group.groups: - return '' - tag = group.groups()[0].split(' ', 1)[0] - if (tag == 'p' or tag == 'br'): - return '\n' - return '' - - return MARKUP_RE.sub(replace_tag, markup) - -def is_iterable(inst): - """Returns whether or not this is a list, tuple, set or dict . - - Note that this does not return true for strings. - """ - return hasattr(inst, '__iter__') - -def is_dict(inst): - """Returns whether or not the specified instance is a dict.""" - return hasattr(inst, 'iteritems') - - -def is_user_defined_new_style_class(obj): - """Returns whether or not the specified instance is a user-defined type.""" - return type(obj).__module__ != '__builtin__' - -def lower_camel_case(s): - """Converts a string to lower camel case. - - Examples: - foo => foo - foo_bar => fooBar - foo__bar => fooBar - foo_bar_baz => fooBarBaz - - Args: - s: The string to convert to lower camel case. - - Returns: - The lower camel cased string. - """ - return reduce(lambda a, b: a + (a and b.capitalize() or b), s.split('_')) - -def non_none_dict(d): - """return a copy of the dictionary without none values.""" - return dict([a for a in d.items() if a[1] is not None]) - -def _serialize_attributes(obj): - """Serializes attributes of an instance. - - Iterates all attributes of an object and invokes serialize if they are - public and not callable. - - Args: - obj: The instance to serialize. - - Returns: - The serialized object. - """ - data = {} - for attr_name in dir(obj): - if attr_name.startswith('_'): - continue - attr = getattr(obj, attr_name) - if attr is None or callable(attr): - continue - # Looks okay, serialize it. - data[lower_camel_case(attr_name)] = serialize(attr) - return data - - -def _serialize_dict(d): - """Invokes serialize on all of its key/value pairs. - - Args: - d: The dict instance to serialize. - - Returns: - The serialized dict. - """ - data = {} - for k, v in d.items(): - data[lower_camel_case(k)] = serialize(v) - return data - - -def serialize(obj): - """Serializes any instance. - - If this is a user-defined instance - type, it will first check for a custom Serialize() function and use that - if it exists. Otherwise, it will invoke serialize all of its public - attributes. Lists and dicts are serialized trivially. - - Args: - obj: The instance to serialize. - - Returns: - The serialized object. - """ - if is_user_defined_new_style_class(obj): - if obj and hasattr(obj, CUSTOM_SERIALIZE_METHOD_NAME): - method = getattr(obj, CUSTOM_SERIALIZE_METHOD_NAME) - if callable(method): - return method() - return _serialize_attributes(obj) - elif is_dict(obj): - return _serialize_dict(obj) - elif is_iterable(obj): - return [serialize(v) for v in obj] - return obj - -def is_valid_proxy_for_id(s): - """ Checks if the given string is a valid proxy id. - - This method asserts whether the string contains reserved characters or not. - This check is to ensure that when we concatenate the robot id and the proxy - id, it doesn't result in an invalid participant id. - - The reserved characters are: - - whitespaces - - non-printing characters: decimal 0 - 31 (hex 00 - 1F), and decimal 127 - (hex 7F) - - @, comma, :, <, and > - If you need to pass in an arbitrary string as the proxy id, please consider - encoding the string with a URL encoder (for example, urllib.quote_plus) or - base64 encoder (for example, base64.b64encode) first. - - Args: - s: the string to be checked. - - Returns: - True if the string is a valid proxy for id. - """ - return RESERVED_PROXY_FOR_CHARS_RE.search(s) == None - -def check_is_valid_proxy_for_id(s): - """ Checks if the given string is a valid proxy id. - - Please see isValidProxyForId(String) for more details on the assertion. This - method raises a ValueError exception if the input string is not a valid proxy - id. - - Args: - s: the string to be checked. - """ - if s != None and not is_valid_proxy_for_id(s): - raise ValueError(s + ' is not a valid proxy for id.') - -class StringEnum(object): - """Enum like class that is configured with a list of values. - - This class effectively implements an enum for Elements, except for that - the actual values of the enums will be the string values. - """ - - def __init__(self, *values): - for name in values: - setattr(self, name, name) http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/util_test.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/util_test.py b/wave/src/main/java/python/api/util_test.py deleted file mode 100644 index 4682821..0000000 --- a/wave/src/main/java/python/api/util_test.py +++ /dev/null @@ -1,187 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Unit tests for the util module.""" - - -__author__ = '[email protected] (David Byttow)' - - -import unittest -import urllib - -import ops -import util - - -class TestUtils(unittest.TestCase): - """Tests utility functions.""" - - def testIsIterable(self): - self.assertTrue(util.is_iterable([])) - self.assertTrue(util.is_iterable({})) - self.assertTrue(util.is_iterable(set())) - self.assertTrue(util.is_iterable(())) - self.assertFalse(util.is_iterable(42)) - self.assertFalse(util.is_iterable('list?')) - self.assertFalse(util.is_iterable(object)) - - def testIsDict(self): - self.assertFalse(util.is_dict([])) - self.assertTrue(util.is_dict({})) - self.assertFalse(util.is_dict(set())) - self.assertFalse(util.is_dict(())) - self.assertFalse(util.is_dict(42)) - self.assertFalse(util.is_dict('dict?')) - self.assertFalse(util.is_dict(object)) - - def testIsUserDefinedNewStyleClass(self): - class OldClass: - pass - - class NewClass(object): - pass - - self.assertFalse(util.is_user_defined_new_style_class(OldClass())) - self.assertTrue(util.is_user_defined_new_style_class(NewClass())) - self.assertFalse(util.is_user_defined_new_style_class({})) - self.assertFalse(util.is_user_defined_new_style_class(())) - self.assertFalse(util.is_user_defined_new_style_class(42)) - self.assertFalse(util.is_user_defined_new_style_class('instance?')) - - def testLowerCamelCase(self): - self.assertEquals('foo', util.lower_camel_case('foo')) - self.assertEquals('fooBar', util.lower_camel_case('foo_bar')) - self.assertEquals('fooBar', util.lower_camel_case('fooBar')) - self.assertEquals('blipId', util.lower_camel_case('blip_id')) - self.assertEquals('fooBar', util.lower_camel_case('foo__bar')) - self.assertEquals('fooBarBaz', util.lower_camel_case('foo_bar_baz')) - self.assertEquals('f', util.lower_camel_case('f')) - self.assertEquals('f', util.lower_camel_case('f_')) - self.assertEquals('', util.lower_camel_case('')) - self.assertEquals('', util.lower_camel_case('_')) - self.assertEquals('aBCDEF', util.lower_camel_case('_a_b_c_d_e_f_')) - - def assertListsEqual(self, a, b): - self.assertEquals(len(a), len(b)) - for i in range(len(a)): - self.assertEquals(a[i], b[i]) - - def assertDictsEqual(self, a, b): - self.assertEquals(len(a.keys()), len(b.keys())) - for k, v in a.iteritems(): - self.assertEquals(v, b[k]) - - def assertNotRaises(self, exception, function, *args): - try: - function(*args) - except ValueError: - fail() - - def testSerializeList(self): - data = [1, 2, 3] - output = util.serialize(data) - self.assertListsEqual(data, output) - - def testSerializeDict(self): - data = {'key': 'value', 'under_score': 'value2'} - expected = {'key': 'value', 'underScore': 'value2'} - output = util.serialize(data) - self.assertDictsEqual(expected, output) - - def testNonNoneDict(self): - a = {'a': 1, 'b': 1} - self.assertDictsEqual(a, util.non_none_dict(a)) - b = a.copy() - b['c'] = None - self.assertDictsEqual(a, util.non_none_dict(b)) - - def testForceUnicode(self): - self.assertEquals(u"aaa", util.force_unicode("aaa")) - self.assertEquals(u"12", util.force_unicode(12)) - self.assertEquals(u"\u0430\u0431\u0432", - util.force_unicode("\xd0\xb0\xd0\xb1\xd0\xb2")) - self.assertEquals(u'\u30e6\u30cb\u30b3\u30fc\u30c9', - util.force_unicode(u'\u30e6\u30cb\u30b3\u30fc\u30c9')) - - def testSerializeAttributes(self): - - class Data(object): - def __init__(self): - self.public = 1 - self._protected = 2 - self.__private = 3 - - def Func(self): - pass - - data = Data() - output = util.serialize(data) - # Functions and non-public fields should not be serialized. - self.assertEquals(1, len(output.keys())) - self.assertEquals(data.public, output['public']) - - def testStringEnum(self): - util.StringEnum() - single = util.StringEnum('foo') - self.assertEquals('foo', single.foo) - multi = util.StringEnum('foo', 'bar') - self.assertEquals('foo', multi.foo) - self.assertEquals('bar', multi.bar) - - def testParseMarkup(self): - self.assertEquals('foo', util.parse_markup('foo')) - self.assertEquals('foo bar', util.parse_markup('foo <b>bar</b>')) - self.assertEquals('foo\nbar', util.parse_markup('foo<br>bar')) - self.assertEquals('foo\nbar', util.parse_markup('foo<p indent="3">bar')) - - def testIsValidProxyForId(self): - self.assertTrue(util.is_valid_proxy_for_id('')) - self.assertTrue(util.is_valid_proxy_for_id('proxyid')) - self.assertTrue(util.is_valid_proxy_for_id('proxy-id1+gmail.com')) - self.assertTrue(util.is_valid_proxy_for_id('proxy-id1_at_gmail.com')) - self.assertTrue(util.is_valid_proxy_for_id('proxy-id%201_at_gmail.com')) - self.assertTrue(util.is_valid_proxy_for_id(urllib.quote('[email protected]'))) - - self.assertFalse(util.is_valid_proxy_for_id('proxy id1')) - self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u0000id1')) - self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u0009id1')) - self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u001Fid1')) - self.assertFalse(util.is_valid_proxy_for_id('proxy@id')) - self.assertFalse(util.is_valid_proxy_for_id('proxy,id')) - self.assertFalse(util.is_valid_proxy_for_id('proxy:id')) - self.assertFalse(util.is_valid_proxy_for_id('proxy<id')) - self.assertFalse(util.is_valid_proxy_for_id('proxy>id')) - self.assertFalse(util.is_valid_proxy_for_id(u'proxy\u007Fid')) - - def testCheckIsValidProxyForId(self): - self.assertRaises(ValueError, util.check_is_valid_proxy_for_id, - '[email protected]') - self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id, - None) - self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id, - '') - self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id, - 'foo+bar.com') - self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id, - urllib.quote('[email protected]')) - self.assertNotRaises(ValueError, util.check_is_valid_proxy_for_id, None) - -if __name__ == '__main__': - unittest.main() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/wavelet.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/wavelet.py b/wave/src/main/java/python/api/wavelet.py deleted file mode 100644 index c3352e4..0000000 --- a/wave/src/main/java/python/api/wavelet.py +++ /dev/null @@ -1,481 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Defines classes that are needed to model a wavelet.""" - -import blip -import errors -import util - - -class DataDocs(object): - """Class modeling a bunch of data documents in pythonic way.""" - - def __init__(self, init_docs, wave_id, wavelet_id, operation_queue): - self._docs = init_docs - self._wave_id = wave_id - self._wavelet_id = wavelet_id - self._operation_queue = operation_queue - - def __iter__(self): - return self._docs.__iter__() - - def __contains__(self, key): - return key in self._docs - - def __delitem__(self, key): - if not key in self._docs: - return - self._operation_queue.wavelet_datadoc_set( - self._wave_id, self._wavelet_id, key, None) - del self._docs[key] - - def __getitem__(self, key): - return self._docs[key] - - def __setitem__(self, key, value): - self._operation_queue.wavelet_datadoc_set( - self._wave_id, self._wavelet_id, key, value) - if value is None and key in self._docs: - del self._docs[key] - else: - self._docs[key] = value - - def __len__(self): - return len(self._docs) - - def keys(self): - return self._docs.keys() - - def serialize(self): - """Returns a dictionary of the data documents.""" - return self._docs - - -class Participants(object): - """Class modelling a set of participants in pythonic way.""" - - #: Designates full access (read/write) role. - ROLE_FULL = "FULL" - - #: Designates read-only role. - ROLE_READ_ONLY = "READ_ONLY" - - def __init__(self, participants, roles, wave_id, wavelet_id, operation_queue): - self._participants = set(participants) - self._roles = roles.copy() - self._wave_id = wave_id - self._wavelet_id = wavelet_id - self._operation_queue = operation_queue - - def __contains__(self, participant): - return participant in self._participants - - def __len__(self): - return len(self._participants) - - def __iter__(self): - return self._participants.__iter__() - - def add(self, participant_id): - """Adds a participant by their ID (address).""" - self._operation_queue.wavelet_add_participant( - self._wave_id, self._wavelet_id, participant_id) - self._participants.add(participant_id) - - def get_role(self, participant_id): - """Return the role for the given participant_id.""" - return self._roles.get(participant_id, Participants.ROLE_FULL) - - def set_role(self, participant_id, role): - """Sets the role for the given participant_id.""" - if role != Participants.ROLE_FULL and role != Participants.ROLE_READ_ONLY: - raise ValueError(role + ' is not a valid role') - self._operation_queue.wavelet_modify_participant_role( - self._wave_id, self._wavelet_id, participant_id, role) - self._roles[participant_id] = role - - def serialize(self): - """Returns a list of the participants.""" - return list(self._participants) - - -class Tags(object): - """Class modelling a list of tags.""" - def __init__(self, tags, wave_id, wavelet_id, operation_queue): - self._tags = list(tags) - self._wave_id = wave_id - self._wavelet_id = wavelet_id - self._operation_queue = operation_queue - - def __getitem__(self, index): - return self._tags[index] - - def __len__(self): - return len(self._tags) - - def __iter__(self): - return self._tags.__iter__() - - def append(self, tag): - """Appends a tag if it doesn't already exist.""" - tag = util.force_unicode(tag) - if tag in self._tags: - return - self._operation_queue.wavelet_modify_tag( - self._wave_id, self._wavelet_id, tag) - self._tags.append(tag) - - def remove(self, tag): - """Removes a tag if it exists.""" - tag = util.force_unicode(tag) - if not tag in self._tags: - return - self._operation_queue.wavelet_modify_tag( - self._wave_id, self._wavelet_id, tag, modify_how='remove') - self._tags.remove(tag) - - def serialize(self): - """Returns a list of tags.""" - return list(self._tags) - - -class BlipThread(object): - """ Models a group of blips in a wave.""" - - def __init__(self, id, location, blip_ids, all_blips, operation_queue): - self._id = id - self._location = location - self._blip_ids = blip_ids - self._all_blips = all_blips - self._operation_queue = operation_queue - - @property - def id(self): - """Returns this thread's id.""" - return self._id - - @property - def location(self): - """Returns this thread's location.""" - return self._location - - @property - def blip_ids(self): - """Returns the blip IDs in this thread.""" - return self._blip_ids - - @property - def blips(self): - """Returns the blips in this thread.""" - blips = [] - for blip_id in self._blip_ids: - blips.append(self._all_blips[blip_id]) - return blips - - def _add_internal(self, blip): - """Adds a blip to the thread, sends out no operations.""" - self._blip_ids.append(blip.blip_id) - self._all_blips[blip.blip_id] = blip - - def serialize(self): - """ Returns serialized properties.""" - return {'id': self._id, - 'location': self._location, - 'blipIds': self._blip_ids} - - -class Wavelet(object): - """Models a single wavelet. - - A single wavelet is composed of metadata, participants, and its blips. - To guarantee that all blips are available, specify Context.ALL for events. - """ - - def __init__(self, json, blips, root_thread, operation_queue, raw_deltas=None): - """Inits this wavelet with JSON data. - - Args: - json: JSON data dictionary from Wave server. - blips: a dictionary object that can be used to resolve blips. - root_thread: a BlipThread object containing the blips in the root thread. - operation_queue: an OperationQueue object to be used to - send any generated operations to. - """ - self._operation_queue = operation_queue - self._root_thread = root_thread - self._wave_id = json.get('waveId') - self._wavelet_id = json.get('waveletId') - self._creator = json.get('creator') - self._raw_deltas = raw_deltas - self._raw_snapshot = json.get('rawSnapshot') - self._creation_time = json.get('creationTime', 0) - self._data_documents = DataDocs(json.get('dataDocuments', {}), - self._wave_id, - self._wavelet_id, - operation_queue) - self._last_modified_time = json.get('lastModifiedTime') - self._participants = Participants(json.get('participants', []), - json.get('participantRoles', {}), - self._wave_id, - self._wavelet_id, - operation_queue) - self._title = json.get('title', '') - self._tags = Tags(json.get('tags', []), - self._wave_id, - self._wavelet_id, - operation_queue) - - self._raw_data = json - self._blips = blip.Blips(blips) - self._root_blip_id = json.get('rootBlipId') - if self._root_blip_id and self._root_blip_id in self._blips: - self._root_blip = self._blips[self._root_blip_id] - else: - self._root_blip = None - self._robot_address = None - - @property - def wavelet_id(self): - """Returns this wavelet's id.""" - return self._wavelet_id - - @property - def wave_id(self): - """Returns this wavelet's parent wave id.""" - return self._wave_id - - @property - def creator(self): - """Returns the participant id of the creator of this wavelet.""" - return self._creator - - @property - def creation_time(self): - """Returns the time that this wavelet was first created in milliseconds.""" - return self._creation_time - - @property - def data_documents(self): - """Returns the data documents for this wavelet based on key name.""" - return self._data_documents - - @property - def domain(self): - """Return the domain that wavelet belongs to.""" - p = self._wave_id.find('!') - if p == -1: - return None - else: - return self._wave_id[:p] - - @property - def last_modified_time(self): - """Returns the time that this wavelet was last modified in ms.""" - return self._last_modified_time - - @property - def participants(self): - """Returns a set of participants on this wavelet.""" - return self._participants - - @property - def root_thread(self): - """Returns the root thread of this wavelet.""" - return self._root_thread - - @property - def tags(self): - """Returns a list of tags for this wavelet.""" - return self._tags - - @property - def raw_deltas(self): - """If present, return the raw deltas for this wavelet.""" - return self._raw_deltas - - @property - def raw_snapshot(self): - """If present, return the raw snapshot for this wavelet.""" - return self._raw_snapshot - - def _get_title(self): - return self._title - - def _set_title(self, title): - title = util.force_unicode(title) - - if title.find('\n') != -1: - raise errors.Error('Wavelet title should not contain a newline ' + - 'character. Specified: ' + title) - - self._operation_queue.wavelet_set_title(self.wave_id, self.wavelet_id, - title) - self._title = title - - # Adjust the content of the root blip, if it is available in the context. - if self._root_blip: - content = '\n' - splits = self._root_blip._content.split('\n', 2) - if len(splits) == 3: - content += splits[2] - self._root_blip._content = '\n' + title + content - - #: Returns or sets the wavelet's title. - title = property(_get_title, _set_title, - doc='Get or set the title of the wavelet.') - - def _get_robot_address(self): - return self._robot_address - - def _set_robot_address(self, address): - if self._robot_address: - raise errors.Error('robot address already set') - self._robot_address = address - - robot_address = property(_get_robot_address, _set_robot_address, - doc='Get or set the address of the current robot.') - - @property - def root_blip(self): - """Returns this wavelet's root blip.""" - return self._root_blip - - @property - def blips(self): - """Returns the blips for this wavelet.""" - return self._blips - - def get_operation_queue(self): - """Returns the OperationQueue for this wavelet.""" - return self._operation_queue - - def serialize(self): - """Return a dict of the wavelet properties.""" - return {'waveId': self._wave_id, - 'waveletId': self._wavelet_id, - 'creator': self._creator, - 'creationTime': self._creation_time, - 'dataDocuments': self._data_documents.serialize(), - 'lastModifiedTime': self._last_modified_time, - 'participants': self._participants.serialize(), - 'title': self._title, - 'blips': self._blips.serialize(), - 'rootBlipId': self._root_blip_id, - 'rootThread': self._root_thread.serialize() - } - - def proxy_for(self, proxy_for_id): - """Return a view on this wavelet that will proxy for the specified id. - - A shallow copy of the current wavelet is returned with the proxy_for_id - set. Any modifications made to this copy will be done using the - proxy_for_id, i.e. the robot+<proxy_for_id>@appspot.com address will - be used. - - If the wavelet was retrieved using the Active Robot API, that is - by fetch_wavelet, then the address of the robot must be added to the - wavelet by setting wavelet.robot_address before calling proxy_for(). - """ - util.check_is_valid_proxy_for_id(proxy_for_id) - self.add_proxying_participant(proxy_for_id) - operation_queue = self.get_operation_queue().proxy_for(proxy_for_id) - res = Wavelet(json={}, - blips={}, root_thread=None, - operation_queue=operation_queue) - res._wave_id = self._wave_id - res._wavelet_id = self._wavelet_id - res._creator = self._creator - res._creation_time = self._creation_time - res._data_documents = self._data_documents - res._last_modified_time = self._last_modified_time - res._participants = self._participants - res._title = self._title - res._raw_data = self._raw_data - res._blips = self._blips - res._root_blip = self._root_blip - res._root_thread = self._root_thread - return res - - def add_proxying_participant(self, id): - """Ads a proxying participant to the wave. - - Proxying participants are of the form [email protected]. This - convenience method constructs this id and then calls participants.add. - """ - if not self.robot_address: - raise errors.Error( - 'Need a robot address to add a proxying for participant') - robotid, domain = self.robot_address.split('@', 1) - if '#' in robotid: - robotid, version = robotid.split('#') - else: - version = None - if '+' in robotid: - newid = robotid.split('+', 1)[0] + '+' + id - else: - newid = robotid + '+' + id - if version: - newid += '#' + version - newid += '@' + domain - self.participants.add(newid) - - def submit_with(self, other_wavelet): - """Submit this wavelet when the passed other wavelet is submited. - - wavelets constructed outside of the event callback need to - be either explicitly submited using robot.submit(wavelet) or be - associated with a different wavelet that will be submited or - is part of the event callback. - """ - other_wavelet._operation_queue.copy_operations(self._operation_queue) - self._operation_queue = other_wavelet._operation_queue - - def reply(self, initial_content=None): - """Replies to the conversation in this wavelet. - - Args: - initial_content: If set, start with this (string) content. - - Returns: - A transient version of the blip that contains the reply. - """ - if not initial_content: - initial_content = u'\n' - initial_content = util.force_unicode(initial_content) - blip_data = self._operation_queue.wavelet_append_blip( - self.wave_id, self.wavelet_id, initial_content) - - instance = blip.Blip(blip_data, self._blips, self._operation_queue) - self._blips._add(instance) - self.root_blip.child_blip_ids.append(instance.blip_id) - return instance - - def delete(self, todelete): - """Remove a blip from this wavelet. - - Args: - todelete: either a blip or a blip id to be removed. - """ - if isinstance(todelete, blip.Blip): - blip_id = todelete.blip_id - else: - blip_id = todelete - self._operation_queue.blip_delete(self.wave_id, self.wavelet_id, blip_id) - self._blips._remove_with_id(blip_id) http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/wavelet_test.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/wavelet_test.py b/wave/src/main/java/python/api/wavelet_test.py deleted file mode 100644 index a238eb7..0000000 --- a/wave/src/main/java/python/api/wavelet_test.py +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Unit tests for the wavelet module.""" - - -import unittest - -import blip -import element -import ops -import wavelet - -import simplejson - -ROBOT_NAME = '[email protected]' - -TEST_WAVELET_DATA = { - 'creator': ROBOT_NAME, - 'creationTime': 100, - 'lastModifiedTime': 101, - 'participants': [ROBOT_NAME], - 'participantsRoles': {ROBOT_NAME: wavelet.Participants.ROLE_FULL}, - 'rootBlipId': 'blip-1', - 'title': 'Title', - 'waveId': 'test.com!w+g3h3im', - 'waveletId': 'test.com!root+conv', - 'tags': ['tag1', 'tag2'], - 'rootThread': { - 'id': '', - 'location': -1, - 'blipIds': ['blip-1'] - } -} - -TEST_BLIP_DATA = { - 'blipId': TEST_WAVELET_DATA['rootBlipId'], - 'childBlipIds': [], - 'content': '\ntesting', - 'contributors': [TEST_WAVELET_DATA['creator'], '[email protected]'], - 'creator': TEST_WAVELET_DATA['creator'], - 'lastModifiedTime': TEST_WAVELET_DATA['lastModifiedTime'], - 'parentBlipId': None, - 'waveId': TEST_WAVELET_DATA['waveId'], - 'elements': {}, - 'waveletId': TEST_WAVELET_DATA['waveletId'], - 'replyThreadIds': [], - 'threadId': '' -} - - -class TestWavelet(unittest.TestCase): - """Tests the wavelet class.""" - - def setUp(self): - self.operation_queue = ops.OperationQueue() - self.all_blips = {} - self.blip = blip.Blip(TEST_BLIP_DATA, - self.all_blips, - self.operation_queue) - self.all_blips[self.blip.blip_id] = self.blip - root_thread_data = TEST_WAVELET_DATA.get('rootThread') - root_thread = wavelet.BlipThread('', - root_thread_data.get('location'), - root_thread_data.get('blipIds', []), - self.all_blips, - self.operation_queue) - - self.wavelet = wavelet.Wavelet(TEST_WAVELET_DATA, - self.all_blips, - root_thread, - self.operation_queue) - self.wavelet.robot_address = ROBOT_NAME - - def testWaveletProperties(self): - w = self.wavelet - self.assertEquals(TEST_WAVELET_DATA['creator'], w.creator) - self.assertEquals(TEST_WAVELET_DATA['creationTime'], w.creation_time) - self.assertEquals(TEST_WAVELET_DATA['lastModifiedTime'], - w.last_modified_time) - self.assertEquals(len(TEST_WAVELET_DATA['participants']), - len(w.participants)) - self.assertTrue(TEST_WAVELET_DATA['participants'][0] in w.participants) - self.assertEquals(TEST_WAVELET_DATA['rootBlipId'], w.root_blip.blip_id) - self.assertEquals(TEST_WAVELET_DATA['title'], w.title) - self.assertEquals(TEST_WAVELET_DATA['waveId'], w.wave_id) - self.assertEquals(TEST_WAVELET_DATA['waveletId'], w.wavelet_id) - self.assertEquals(TEST_WAVELET_DATA['rootThread']['id'], w.root_thread.id) - self.assertEquals(TEST_WAVELET_DATA['rootThread']['location'], - w.root_thread.location) - self.assertEquals(len(TEST_WAVELET_DATA['rootThread']['blipIds']), - len(w.root_thread.blips)) - self.assertEquals('test.com', w.domain) - - def testWaveletMethods(self): - w = self.wavelet - reply = w.reply() - self.assertEquals(2, len(w.blips)) - w.delete(reply) - self.assertEquals(1, len(w.blips)) - self.assertEquals(0, len(w.data_documents)) - self.wavelet.data_documents['key'] = 'value' - self.assert_('key' in w.data_documents) - self.assertEquals(1, len(w.data_documents)) - for key in w.data_documents: - self.assertEquals(key, 'key') - self.assertEquals(1, len(w.data_documents.keys())) - self.wavelet.data_documents['key'] = None - self.assertEquals(0, len(w.data_documents)) - num_participants = len(w.participants) - w.proxy_for('proxy').reply() - self.assertEquals(2, len(w.blips)) - # check that the new proxy for participant was added - self.assertEquals(num_participants + 1, len(w.participants)) - w._robot_address = ROBOT_NAME.replace('@', '+proxy@') - w.proxy_for('proxy').reply() - self.assertEquals(num_participants + 1, len(w.participants)) - self.assertEquals(3, len(w.blips)) - - def testSetTitle(self): - self.blip._content = '\nOld title\n\nContent' - self.wavelet.title = 'New title \xd0\xb0\xd0\xb1\xd0\xb2' - self.assertEquals(1, len(self.operation_queue)) - self.assertEquals('wavelet.setTitle', - self.operation_queue.serialize()[1]['method']) - self.assertEquals(u'\nNew title \u0430\u0431\u0432\n\nContent', - self.blip._content) - - def testSetTitleAdjustRootBlipWithOneLineProperly(self): - self.blip._content = '\nOld title' - self.wavelet.title = 'New title' - self.assertEquals(1, len(self.operation_queue)) - self.assertEquals('wavelet.setTitle', - self.operation_queue.serialize()[1]['method']) - self.assertEquals('\nNew title\n', self.blip._content) - - def testSetTitleAdjustEmptyRootBlipProperly(self): - self.blip._content = '\n' - self.wavelet.title = 'New title' - self.assertEquals(1, len(self.operation_queue)) - self.assertEquals('wavelet.setTitle', - self.operation_queue.serialize()[1]['method']) - self.assertEquals('\nNew title\n', self.blip._content) - - def testTags(self): - w = self.wavelet - self.assertEquals(2, len(w.tags)) - w.tags.append('tag3') - self.assertEquals(3, len(w.tags)) - w.tags.append('tag3') - self.assertEquals(3, len(w.tags)) - w.tags.remove('tag1') - self.assertEquals(2, len(w.tags)) - self.assertEquals('tag2', w.tags[0]) - - def testParticipantRoles(self): - w = self.wavelet - self.assertEquals(wavelet.Participants.ROLE_FULL, - w.participants.get_role(ROBOT_NAME)) - w.participants.set_role(ROBOT_NAME, wavelet.Participants.ROLE_READ_ONLY) - self.assertEquals(wavelet.Participants.ROLE_READ_ONLY, - w.participants.get_role(ROBOT_NAME)) - - def testSerialize(self): - self.blip.append(element.Gadget('http://test.com', {'a': 3})) - self.wavelet.title = 'A wavelet title' - self.blip.append(element.Image(url='http://www.google.com/logos/clickortreat1.gif', - width=320, height=118)) - self.blip.append(element.Attachment(caption='fake', data='fake data')) - self.blip.append(element.Line(line_type='li', indent='2')) - self.blip.append('bulleted!') - self.blip.append(element.Installer( - 'http://wave-skynet.appspot.com/public/extensions/areyouin/manifest.xml')) - self.wavelet.proxy_for('proxy').reply().append('hi from douwe') - inlineBlip = self.blip.insert_inline_blip(5) - inlineBlip.append('hello again!') - - serialized = self.wavelet.serialize() - serialized = simplejson.dumps(serialized) - self.assertTrue(serialized.find('test.com') > 0) - -if __name__ == '__main__': - unittest.main() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/waveservice.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/waveservice.py b/wave/src/main/java/python/api/waveservice.py deleted file mode 100644 index 444a26b..0000000 --- a/wave/src/main/java/python/api/waveservice.py +++ /dev/null @@ -1,468 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Base class to use OAuth to talk to the wave service.""" - -import httplib -import logging -import urllib -import urlparse - -import oauth -import simplejson - -import ops -import blip -import errors -import events -import search -import util -import wavelet - - -class WaveService(object): - # Google OAuth URLs - REQUEST_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetRequestToken' - ACCESS_TOKEN_URL = 'https://www.google.com/accounts/OAuthGetAccessToken' - AUTHORIZATION_URL = 'https://www.google.com/accounts/OAuthAuthorizeToken' - - # Wave OAuth URLS - SCOPE = 'http://wave.googleusercontent.com/api/rpc' - SIGNATURE_METHOD = oauth.OAuthSignatureMethod_HMAC_SHA1() - - # Wave RPC URLs - RPC_URL = 'https://www-opensocial.googleusercontent.com/api/rpc' - SANDBOX_RPC_URL = ( - 'https://www-opensocial-sandbox.googleusercontent.com/api/rpc') - - def __init__(self, use_sandbox=False, server_rpc_base=None, - consumer_key='anonymous', consumer_secret='anonymous', - http_post=None): - """Initializes a service that can perform the various OAuth steps. - - Args: - use_sandbox: A boolean indicating whether to use Wave Sandbox URLs - server_rpc_base: optional explicit url to use for rpc, - overriding use_sandbox. - consumer_key: A string for the consumer key, defaults to 'anonymous' - consumer_secret: A string for the consumer secret, defaults to 'anonymous' - http_post: handler to call to execute a http post. - """ - self._consumer = oauth.OAuthConsumer(consumer_key, consumer_secret) - logging.info('server_rpc_base: %s', server_rpc_base) - if server_rpc_base: - self._server_rpc_base = server_rpc_base - elif use_sandbox: - self._server_rpc_base = WaveService.SANDBOX_RPC_URL - else: - self._server_rpc_base = WaveService.RPC_URL - logging.info('server:' + self._server_rpc_base) - - self._http_post = self.http_post - self._connection = httplib.HTTPSConnection('www.google.com') - self._access_token = None - - def _make_token(self, token): - """If passed an oauth token, return that. If passed a string, convert.""" - if isinstance(token, basestring): - return oauth.OAuthToken.from_string(token) - else: - return token - - def set_http_post(self, http_post): - """Set the http_post handler to use when posting.""" - self._http_post = http_post - - def get_token_from_request(self, oauth_request): - """Convenience function to returning the token from a request. - - Args: - oauth_request: An OAuthRequest object - Returns: - An OAuthToken object - """ - # Send request to the request token URL - self._connection.request(oauth_request.http_method, oauth_request.to_url()) - - # Extract token from response - response = self._connection.getresponse().read() - self._request_token = oauth.OAuthToken.from_string(response) - return self._request_token - - def fetch_request_token(self, callback=None): - """Fetches the request token to start the oauth dance. - - Args: - callback: the URL to where the service will redirect to after - access is granted. - Returns: - An OAuthToken object - """ - # Create and sign OAuth request - params = {'scope': WaveService.SCOPE} - if callback: - params['oauth_callback'] = callback - oauth_request = oauth.OAuthRequest.from_consumer_and_token(self._consumer, - http_url=WaveService.REQUEST_TOKEN_URL, parameters=params) - oauth_request.sign_request(WaveService.SIGNATURE_METHOD, self._consumer, None) - - return self.get_token_from_request(oauth_request) - - def generate_authorization_url(self, request_token=None): - """Generates the authorization URL (Step 2). - - Args: - request_token: An OAuthToken object - Returns: - An authorization URL - """ - # Create Authorization URL request - if request_token is None: - request_token = self._request_token - oauth_request = oauth.OAuthRequest.from_token_and_callback( - token=request_token, http_url=WaveService.AUTHORIZATION_URL) - - # Send request - self._connection.request(oauth_request.http_method, oauth_request.to_url()) - - # Extract location from the response - response = self._connection.getresponse() - return response.getheader('location') - - def upgrade_to_access_token(self, request_token, verifier=None): - """Upgrades the request_token to an access token (Step 3). - - Args: - request_token: An OAuthToken object or string - verifier: A verifier string - Returns: - An OAuthToken object - """ - request_token = self._make_token(request_token) - params = {} - if verifier: - params['oauth_verifier'] = verifier - oauth_request = oauth.OAuthRequest.from_consumer_and_token(self._consumer, - token=request_token, http_url=WaveService.ACCESS_TOKEN_URL, - parameters=params) - oauth_request.sign_request(WaveService.SIGNATURE_METHOD, self._consumer, - request_token) - - self._access_token = self.get_token_from_request(oauth_request) - return self._access_token - - def set_access_token(self, access_token): - self._access_token = self._make_token(access_token) - - def http_post(self, url, data, headers): - """Execute an http post. - - You can provide a different method to use in the constructor. This - is mostly useful when running on app engine and you want to set - the time out to something different than the default 5 seconds. - - Args: - url: to post to - body: post body - headers: extra headers to pass along - Returns: - response_code, returned_page - """ - import urllib2 - req = urllib2.Request(url, - data=data, - headers=headers) - try: - f = urllib2.urlopen(req) - return f.code, f.read() - except urllib2.HTTPError, e: - return e.code, e.read() - - def make_rpc(self, operations): - """Make an rpc call, submitting the specified operations.""" - - rpc_host = urlparse.urlparse(self._server_rpc_base).netloc - - # We either expect an operationqueue, a single op or a list - # of ops: - if (not isinstance(operations, ops.OperationQueue)): - if not isinstance(operations, list): - operations = [operations] - queue = ops.OperationQueue() - queue.copy_operations(operations) - else: - queue = operations - - - data = simplejson.dumps(queue.serialize(method_prefix='wave')) - - oauth_request = oauth.OAuthRequest.from_consumer_and_token(self._consumer, - token=self._access_token, http_method='POST', - http_url=self._server_rpc_base) - oauth_request.sign_request(WaveService.SIGNATURE_METHOD, - self._consumer, self._access_token) - - logging.info('Active URL: %s' % self._server_rpc_base) - logging.info('Active Outgoing: %s' % data) - headers = {'Content-Type': 'application/json'} - headers.update(oauth_request.to_header()); - status, content = self._http_post( - url=self._server_rpc_base, - data=data, - headers=headers) - - if status != 200: - raise errors.RpcError('code: %s\n%s' % (status, content)) - return simplejson.loads(content) - - def _first_rpc_result(self, result): - """result is returned from make_rpc. Get the first data record - or throw an exception if it was an error. Ignore responses to - NOTIFY_OP_ID.""" - result = [record for record in result if record['id'] != ops.NOTIFY_OP_ID] - if not result: - raise errors.RpcError('No results found.') - result = result[0] - error = result.get('error') - if error: - raise errors.RpcError(str(error['code']) - + ': ' + error['message']) - data = result.get('data') - if data is not None: - return data - raise errors.Error('RPC Error: No data record.') - - def _wavelet_from_json(self, json, pending_ops): - """Construct a wavelet from the passed json. - - The json should either contain a wavelet and a blips record that - define those respective object. The returned wavelet - will be constructed using the passed pending_ops - OperationQueue. - Alternatively the json can be the result of a previous - wavelet.serialize() call. In that case the blips will - be contaned in the wavelet record. - """ - if isinstance(json, basestring): - json = simplejson.loads(json) - - # Create blips dict so we can pass into BlipThread objects - blips = {} - - # Setup threads first, as the Blips and Wavelet need to know about them - threads = {} - # In case of blind_wavelet or new_wave, we may not have threads indo - threads_data = json.get('threads', {}) - # Create remaining thread objects - for thread_id, raw_thread_data in threads_data.items(): - threads[thread_id] = wavelet.BlipThread(thread_id, - raw_thread_data.get('location'), raw_thread_data.get('blipIds', []), - blips, pending_ops) - - # If being called from blind_wavelet, wavelet is top level info - if 'wavelet' in json: - raw_wavelet_data = json['wavelet'] - elif 'waveletData' in json: - raw_wavelet_data = json['waveletData'] - else: - raw_wavelet_data = json - root_thread_data = raw_wavelet_data.get('rootThread') - root_thread = wavelet.BlipThread('', - root_thread_data.get('location'), - root_thread_data.get('blipIds', []), - blips, - pending_ops) - threads[''] = root_thread - - # Setup the blips, pass in reply threads - for blip_id, raw_blip_data in json['blips'].items(): - reply_threads = [threads[id] for id in raw_blip_data.get('replyThreadIds', - [])] - thread = threads.get(raw_blip_data.get('threadId')) - blips[blip_id] = blip.Blip(raw_blip_data, blips, pending_ops, - thread=thread, reply_threads=reply_threads) - - result = wavelet.Wavelet(raw_wavelet_data, blips, root_thread, pending_ops, - raw_deltas=json.get('rawDeltas')) - - robot_address = json.get('robotAddress') - if robot_address: - result.robot_address = robot_address - - return result - - def search(self, query, index=None, num_results=None): - """Execute a search request. - - Args: - query: what to search for, for example [in:inbox] - index: index of the first result to return - num_results: how many results to return - """ - operation_queue = ops.OperationQueue() - operation_queue.robot_search(query, index, num_results) - result = self._first_rpc_result(self.make_rpc(operation_queue)) - return search.Results(result) - - def new_wave(self, domain, participants=None, message='', proxy_for_id=None, - submit=False): - """Create a new wave with the initial participants on it. - - A new wave is returned with its own operation queue. It the - responsibility of the caller to make sure this wave gets - submitted to the server, either by calling robot.submit() or - by calling .submit_with() on the returned wave. - - Args: - domain: the domain to create the wavelet on. This should - in general correspond to the domain of the incoming - wavelet. (wavelet.domain). Exceptions are situations - where the robot is calling new_wave outside of an - event or when the server is handling multiple domains. - - participants: initial participants on the wave. The robot - as the creator of the wave is always added. - - message: a string that will be passed back to the robot - when the WAVELET_CREATOR event is fired. This is a - lightweight way to pass around state. - - submit: if true, use the active gateway to make a round - trip to the server. This will return immediately an - actual waveid/waveletid and blipId for the root blip. - - """ - util.check_is_valid_proxy_for_id(proxy_for_id) - operation_queue = ops.OperationQueue(proxy_for_id) - if not isinstance(message, basestring): - message = simplejson.dumps(message) - - # Create temporary wavelet data - blip_data, wavelet_data = operation_queue.robot_create_wavelet( - domain=domain, - participants=participants, - message=message) - - # Create temporary blips dictionary - blips = {} - root_blip = blip.Blip(blip_data, blips, operation_queue) - blips[root_blip.blip_id] = root_blip - - if submit: - # Submit operation to server and return actual wave/blip IDs - temp_wavelet = wavelet.Wavelet(wavelet_data, - blips=blips, - root_thread=None, - operation_queue=operation_queue) - result = self._first_rpc_result(self.submit(temp_wavelet)) - if isinstance(result, list): - result = result[0] - if 'blipId' in result: - blip_data['blipId'] = result['blipId'] - wavelet_data['rootBlipId'] = result['blipId'] - for field in 'waveId', 'waveletId': - if field in result: - wavelet_data[field] = result[field] - blip_data[field] = result[field] - blips = {} - root_blip = blip.Blip(blip_data, blips, operation_queue) - blips[root_blip.blip_id] = root_blip - - root_thread = wavelet.BlipThread('', - -1, - [root_blip.blip_id], - blips, - operation_queue) - new_wavelet = wavelet.Wavelet(wavelet_data, - blips=blips, - root_thread=root_thread, - operation_queue=operation_queue) - return new_wavelet - - def fetch_wavelet(self, wave_id, wavelet_id=None, proxy_for_id=None, - raw_deltas_from_version=-1, return_raw_snapshot=False): - """Use the REST interface to fetch a wave and return it. - - The returned wavelet contains a snapshot of the state of the - wavelet at that point. It can be used to modify the wavelet, - but the wavelet might change in between, so treat carefully. - - Also note that the wavelet returned has its own operation - queue. It the responsibility of the caller to make sure this - wavelet gets submited to the server, either by calling - robot.submit() or by calling .submit_with() on the returned - wavelet. - - Args: - wave_id: the wave id - wavelet_id: the wavelet_id - proxy_for_id: on whose behalf to execute the operation - raw_deltas_from_version: If specified, return a raw dump of the - delta history of this wavelet, starting at the given version. - This may return only part of the history; use additional - requests with higher raw_deltas_from_version parameters to - get the rest. - return_raw_snapshot: if true, return the raw data for this - wavelet. - """ - util.check_is_valid_proxy_for_id(proxy_for_id) - if not wavelet_id: - domain, id = wave_id.split('!', 1) - wavelet_id = domain + '!conv+root' - operation_queue = ops.OperationQueue(proxy_for_id) - operation_queue.robot_fetch_wave(wave_id, wavelet_id, - raw_deltas_from_version, return_raw_snapshot) - result = self._first_rpc_result(self.make_rpc(operation_queue)) - return self._wavelet_from_json(result, ops.OperationQueue(proxy_for_id)) - - def blind_wavelet(self, json, proxy_for_id=None): - """Construct a blind wave from a json string. - - Call this method if you have a snapshot of a wave that you - want to operate on outside of an event. Since the wave might - have changed since you last saw it, you should take care to - submit operations that are as safe as possible. - - Args: - json: a json object or string containing at least a key - wavelet defining the wavelet and a key blips defining the - blips in the view. - - proxy_for_id: the proxying information that will be set on the wavelet's - operation queue. - - Returns: - A new wavelet with its own operation queue. It the - responsibility of the caller to make sure this wavelet gets - submited to the server, either by calling robot.submit() or - by calling .submit_with() on the returned wavelet. - """ - util.check_is_valid_proxy_for_id(proxy_for_id) - return self._wavelet_from_json(json, ops.OperationQueue(proxy_for_id)) - - def submit(self, wavelet_to_submit): - """Submit the pending operations associated with wavelet_to_submit. - - Typically the wavelet will be the result of fetch_wavelet, blind_wavelet - or new_wave. - """ - pending = wavelet_to_submit.get_operation_queue() - res = self.make_rpc(pending) - pending.clear() - return res http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/waveservice_test.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/waveservice_test.py b/wave/src/main/java/python/api/waveservice_test.py deleted file mode 100644 index da433da..0000000 --- a/wave/src/main/java/python/api/waveservice_test.py +++ /dev/null @@ -1,72 +0,0 @@ -#!/usr/bin/python2.4 -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - -"""Unit tests for the wavelet module.""" - - -import unittest - -import blip -import element -import ops -import wavelet -import waveservice -import simplejson -import testdata - - -class TestWavelet(unittest.TestCase): - """Tests the wavelet class.""" - - def setUp(self): - self.waveservice = waveservice.WaveService() - - def testWaveletProperties(self): - operation_queue = ops.OperationQueue() - TEST_DATA = simplejson.loads(testdata.json_string) - w = self.waveservice._wavelet_from_json(TEST_DATA, - operation_queue) - self.assertEquals(TEST_DATA['wavelet']['waveId'], w.wave_id) - self.assertEquals(TEST_DATA['wavelet']['rootThread']['id'], - w.root_thread.id) - self.assertEquals(TEST_DATA['wavelet']['rootThread']['location'], - w.root_thread.location) - self.assertEquals(len(TEST_DATA['wavelet']['rootThread']['blipIds']), - len(w.root_thread.blips)) - - b = w.root_blip - self.assertEquals(len(TEST_DATA['blips']['b+IvD7RCuWB']['replyThreadIds']), - len(b.reply_threads)) - - - def testWaveletBlipMethods(self): - operation_queue = ops.OperationQueue() - TEST_DATA = simplejson.loads(testdata.json_string) - w = self.waveservice._wavelet_from_json(TEST_DATA, - operation_queue) - root_blip = w.root_blip - blip = root_blip.continue_thread() - self.assertEquals(blip.parent_blip_id, root_blip.parent_blip_id) - self.assertEquals(8, len(w.blips)) - self.assertEquals(4, len(w.root_thread.blips)) - - - -if __name__ == '__main__': - unittest.main()
