http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/robot.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/robot.py b/wave/src/main/java/python/api/robot.py deleted file mode 100644 index 99561f6..0000000 --- a/wave/src/main/java/python/api/robot.py +++ /dev/null @@ -1,343 +0,0 @@ -#!/usr/bin/python -# -# 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 the generic robot classes. - -This module provides the Robot class and RobotListener interface, -as well as some helper functions for web requests and responses. -""" - -import logging -import sys - -try: - __import__('google3') # setup internal test environment -except ImportError: - pass - -import simplejson -import blip -import errors -import ops -import simplejson -import wavelet -import waveservice - -DEFAULT_PROFILE_URL = ( - 'http://code.google.com/apis/wave/extensions/robots/python-tutorial.html') - - -class Robot(object): - """Robot metadata class. - - This class holds on to basic robot information like the name and profile. - It also maintains the list of event handlers and cron jobs and - dispatches events to the appropriate handlers. - """ - - def __init__(self, name, image_url='', profile_url=DEFAULT_PROFILE_URL): - """Initializes self with robot information. - - Args: - name: The name of the robot - image_url: (optional) url of an image that should be used as the avatar - for this robot. - profile_url: (optional) url of a webpage with more information about - this robot. - """ - self._handlers = {} - self._name = name - self._verification_token = None - self._st = None - self._waveservice = waveservice.WaveService() - self._profile_handler = None - self._image_url = image_url - self._profile_url = profile_url - self._capability_hash = 0 - self._consumer_key = None - self._http_post = None - - @property - def name(self): - """Returns the name of the robot.""" - return self._name - - @property - def image_url(self): - """Returns the URL of the avatar image.""" - return self._image_url - - @property - def profile_url(self): - """Returns the URL of an info page for the robot.""" - return self._profile_url - - def get_verification_token_info(self): - """Returns the verification token and ST parameter.""" - return self._verification_token, self._st - - def get_waveservice(self): - """Return the currently installed waveservice if available. - - Raises: - Error: if no service is installed. - """ - if self._waveservice is None: - raise errors.Error('Oauth has not been setup') - return self._waveservice - - def capabilities_hash(self): - """Return the capabilities hash as a hex string.""" - return hex(self._capability_hash) - - def register_handler(self, event_class, handler, context=None, filter=None): - """Registers a handler on a specific event type. - - Multiple handlers may be registered on a single event type and are - guaranteed to be called in order of registration. - - The handler takes two arguments, the event object and the corresponding - wavelet. - - Args: - event_class: An event to listen for from the classes defined in the - events module. - - handler: A function handler which takes two arguments, the wavelet for - the event and the event object. - - context: The context to provide for this handler. - - filter: Depending on the event, a filter can be specified that restricts - for which values the event handler will be called from the server. - Valuable to restrict the amount of traffic send to the robot. - """ - payload = (handler, event_class, context, filter) - self._handlers.setdefault(event_class.type, []).append(payload) - if isinstance(context, list): - context = ','.join(context) - self._capability_hash = (self._capability_hash * 13 + - hash(ops.PROTOCOL_VERSION) + - hash(event_class.type) + - hash(context) + - hash(filter)) & 0xfffffff - - def set_verification_token_info(self, token, st=None): - """Set the verification token used in the ownership verification. - - /wave/robot/register starts this process up and will produce this token. - - Args: - token: the token provided by /wave/robot/register. - - st: optional parameter to verify the request for the token came from - the wave server. - """ - self._verification_token = token - self._st = st - - def set_http_post(self, http_post): - """Set the http_post handler to use when posting.""" - self._http_post = http_post - if self._waveservice: - self._waveservice.set_http_post(http_post) - - def setup_oauth(self, consumer_key, consumer_secret, - server_rpc_base='https://www-opensocial.googleusercontent.com/api/rpc'): - """Configure this robot to use the oauth'd json rpc. - - Args: - consumer_key: consumer key received from the verification process. - - consumer_secret: secret received from the verification process. - - server_rpc_base: url of the rpc gateway to use. Specify None for default. - For wave preview, https://www-opensocial.googleusercontent.com/api/rpc - should be used. - For wave sandbox, - https://www-opensocial-sandbox.googleusercontent.com/api/rpc should be used. - """ - - consumer_key_prefix = '' - # NOTE(ljvderijk): Present for backwards capability. - if server_rpc_base in [waveservice.WaveService.SANDBOX_RPC_URL, - waveservice.WaveService.RPC_URL]: - consumer_key_prefix = 'google.com:' - - self._consumer_key = consumer_key_prefix + consumer_key - self._waveservice = waveservice.WaveService( - consumer_key=consumer_key, - consumer_secret=consumer_secret, - server_rpc_base=server_rpc_base, - http_post=self._http_post) - - def register_profile_handler(self, handler): - """Sets the profile handler for this robot. - - The profile handler will be called when a profile is needed. The handler - gets passed the name for which a profile is needed or None for the - robot itself. A dictionary with keys for name, imageUrl and - profileUrl should be returned. - """ - self._profile_handler = handler - - def capabilities_xml(self): - """Return this robot's capabilities as an XML string.""" - lines = [] - for capability, payloads in self._handlers.items(): - for payload in payloads: - handler, event_class, context, filter = payload - line = ' <w:capability name="%s"' % capability - if context: - if isinstance(context, list): - context = ','.join(context) - line += ' context="%s"' % context - if filter: - line += ' filter="%s"' % filter - line += '/>\n' - lines.append(line) - if self._consumer_key: - oauth_tag = '<w:consumer_key>%s</w:consumer_key>\n' % self._consumer_key - else: - oauth_tag = '' - return ('<?xml version="1.0"?>\n' - '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n' - '<w:version>%s</w:version>\n' - '%s' - '<w:protocolversion>%s</w:protocolversion>\n' - '<w:capabilities>\n' - '%s' - '</w:capabilities>\n' - '</w:robot>\n') % (self.capabilities_hash(), - oauth_tag, - ops.PROTOCOL_VERSION, - '\n'.join(lines)) - - def profile_json(self, name=None): - """Returns a JSON representation of the profile. - - This method is called both for the basic profile of the robot and to - get a proxying for profile, in which case name is set. By default - the information supplied at registration is returned. - - Use register_profile_handler to override this default behavior. - """ - if self._profile_handler: - data = self._profile_handler(name) - else: - data = {'name': self.name, - 'imageUrl': self.image_url, - 'profileUrl': self.profile_url} - return simplejson.dumps(data) - - def process_events(self, json): - """Process an incoming set of events encoded as json.""" - parsed = simplejson.loads(json) - pending_ops = ops.OperationQueue() - event_wavelet = self.get_waveservice()._wavelet_from_json(parsed, pending_ops) - - for event_data in parsed['events']: - for payload in self._handlers.get(event_data['type'], []): - handler, event_class, context, filter = payload - event = event_class(event_data, event_wavelet) - handler(event, event_wavelet) - - pending_ops.set_capability_hash(self.capabilities_hash()) - return simplejson.dumps(pending_ops.serialize()) - - 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. - - """ - return self.get_waveservice().new_wave( - domain, participants, message, proxy_for_id, submit) - - 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. - """ - return self.get_waveservice().fetch_wavelet( - wave_id, wavelet_id, proxy_for_id, raw_deltas_from_version, - return_raw_snapshot) - - 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. - """ - return self.get_waveservice().blind_wavelet(json, 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. - """ - return self.get_waveservice().submit(wavelet_to_submit)
http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/robot_test.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/robot_test.py b/wave/src/main/java/python/api/robot_test.py deleted file mode 100644 index 8d079b1..0000000 --- a/wave/src/main/java/python/api/robot_test.py +++ /dev/null @@ -1,257 +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 robot module.""" - -import unittest - -import events -import ops -import robot -import simplejson - -BLIP_JSON = ('{"wdykLROk*13":' - '{"lastModifiedTime":1242079608457,' - '"contributors":["[email protected]"],' - '"waveletId":"test.com!conv+root",' - '"waveId":"test.com!wdykLROk*11",' - '"parentBlipId":null,' - '"version":3,' - '"creator":"[email protected]",' - '"content":"\\nContent!",' - '"blipId":"wdykLROk*13","' - 'annotations":[{"range":{"start":0,"end":1},' - '"name":"user/e/[email protected]","value":"David"}],' - '"elements":{},' - '"threadId": "",' - '"childBlipIds":[]}' - '}') - -WAVELET_JSON = ('{"lastModifiedTime":1242079611003,' - '"title":"A title",' - '"waveletId":"test.com!conv+root",' - '"rootBlipId":"wdykLROk*13",' - '"dataDocuments":null,' - '"creationTime":1242079608457,' - '"waveId":"test.com!wdykLROk*11",' - '"participants":["[email protected]","[email protected]"],' - '"creator":"[email protected]",' - '"rootThread": ' - '{"id":"", "location": "-1", "blipIds": ["wdykLROk*13"]},' - '"version":5}') - -EVENTS_JSON = ('[{"timestamp":1242079611003,' - '"modifiedBy":"[email protected]",' - '"properties":{"participantsRemoved":[],' - '"participantsAdded":["[email protected]"]},' - '"type":"WAVELET_PARTICIPANTS_CHANGED"}]') - -TEST_JSON = '{"blips":%s,"wavelet":%s,"events":%s, "threads": {}}' % ( - BLIP_JSON, WAVELET_JSON, EVENTS_JSON) - -NEW_WAVE_JSON = [{"data": - {"waveletId": "wavesandbox.com!conv+root", - "blipId": "b+LrODcLZkDlu", "waveId": - "wavesandbox.com!w+LrODcLZkDlt"}, - "id": "op2"}] - - -class TestRobot(unittest.TestCase): - """Tests for testing the basic parsing of json in robots.""" - - def setUp(self): - self.robot = robot.Robot('Testy') - - def testCreateWave(self): - self.robot.get_waveservice().submit = lambda x: NEW_WAVE_JSON - new_wave = self.robot.new_wave('wavesandbox.com', submit=True) - self.assertEqual('wavesandbox.com!w+LrODcLZkDlt', new_wave.wave_id) - - def testEventParsing(self): - def check(event, wavelet): - # Test some basic properties; the rest should be covered by - # ops.CreateContext. - root = wavelet.root_blip - self.assertEqual(1, len(wavelet.blips)) - self.assertEqual('wdykLROk*13', root.blip_id) - self.assertEqual('test.com!wdykLROk*11', root.wave_id) - self.assertEqual('test.com!conv+root', root.wavelet_id) - self.assertEqual('WAVELET_PARTICIPANTS_CHANGED', event.type) - self.assertEqual({'participantsRemoved': [], - 'participantsAdded': ['[email protected]']}, - event.properties) - self.robot.test_called = True - - self.robot.test_called = False - self.robot.register_handler(events.WaveletParticipantsChanged, - check) - json = self.robot.process_events(TEST_JSON) - self.assertTrue(self.robot.test_called) - operations = simplejson.loads(json) - # there should be one operation indicating the current version: - self.assertEqual(1, len(operations)) - - def testWrongEventsIgnored(self): - self.robot.test_called = True - - def check(event, wavelet): - called = True - - self.robot.test_called = False - self.robot.register_handler(events.BlipSubmitted, - check) - self.robot.process_events(TEST_JSON) - self.assertFalse(self.robot.test_called) - - def testOperationParsing(self): - def check(event, wavelet): - wavelet.reply() - wavelet.title = 'new title' - wavelet.root_blip.append_markup('<b>Hello</b>') - - self.robot.register_handler(events.WaveletParticipantsChanged, - check) - json = self.robot.process_events(TEST_JSON) - operations = simplejson.loads(json) - expected = set([ops.ROBOT_NOTIFY, - ops.WAVELET_APPEND_BLIP, - ops.WAVELET_SET_TITLE, - ops.DOCUMENT_APPEND_MARKUP]) - methods = [operation['method'] for operation in operations] - for method in methods: - self.assertTrue(method in expected) - expected.remove(method) - self.assertEquals(0, len(expected)) - - def testSerializeWavelets(self): - wavelet = self.robot.blind_wavelet(TEST_JSON) - serialized = wavelet.serialize() - unserialized = self.robot.blind_wavelet(serialized) - self.assertEquals(wavelet.creator, unserialized.creator) - self.assertEquals(wavelet.creation_time, unserialized.creation_time) - self.assertEquals(wavelet.last_modified_time, - unserialized.last_modified_time) - self.assertEquals(wavelet.root_blip.blip_id, unserialized.root_blip.blip_id) - self.assertEquals(wavelet.title, unserialized.title) - self.assertEquals(wavelet.wave_id, unserialized.wave_id) - self.assertEquals(wavelet.wavelet_id, unserialized.wavelet_id) - self.assertEquals(wavelet.domain, unserialized.domain) - - def testProxiedBlindWavelet(self): - def handler(event, wavelet): - blind_wavelet = self.robot.blind_wavelet(TEST_JSON, 'proxyid') - blind_wavelet.reply() - blind_wavelet.submit_with(wavelet) - - self.robot.register_handler(events.WaveletParticipantsChanged, handler) - json = self.robot.process_events(TEST_JSON) - operations = simplejson.loads(json) - - self.assertEqual(2, len(operations)) - self.assertEquals(ops.ROBOT_NOTIFY, - operations[0]['method']) - self.assertEquals(ops.WAVELET_APPEND_BLIP, operations[1]['method']) - self.assertEquals('proxyid', operations[1]['params']['proxyingFor']) - - def testCapabilitiesHashIncludesContextAndFilter(self): - robot1 = robot.Robot('Robot1') - robot1.register_handler(events.WaveletSelfAdded, lambda: '') - - robot2 = robot.Robot('Robot2') - robot2.register_handler(events.WaveletSelfAdded, lambda: '', - context=events.Context.ALL) - self.assertNotEqual(robot1.capabilities_hash(), robot2.capabilities_hash()) - - robot3 = robot.Robot('Robot3') - robot2.register_handler(events.WaveletSelfAdded, lambda: '', - context=events.Context.ALL, filter="foo") - self.assertNotEqual(robot1.capabilities_hash(), robot2.capabilities_hash()) - self.assertNotEqual(robot1.capabilities_hash(), robot3.capabilities_hash()) - self.assertNotEqual(robot2.capabilities_hash(), robot3.capabilities_hash()) - -class TestGetCapabilitiesXml(unittest.TestCase): - - def setUp(self): - self.robot = robot.Robot('Testy') - self.robot.capabilities_hash = lambda: '1' - - def assertStringsEqual(self, s1, s2): - self.assertEqual(s1, s2, 'Strings differ:\n%s--\n%s' % (s1, s2)) - - def testDefault(self): - expected = ( - '<?xml version="1.0"?>\n' - '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n' - '<w:version>1</w:version>\n' - '<w:protocolversion>%s</w:protocolversion>\n' - '<w:capabilities>\n</w:capabilities>\n' - '</w:robot>\n') % ops.PROTOCOL_VERSION - xml = self.robot.capabilities_xml() - self.assertStringsEqual(expected, xml) - - def testUrls(self): - profile_robot = robot.Robot( - 'Testy', - image_url='http://example.com/image.png', - profile_url='http://example.com/profile.xml') - profile_robot.capabilities_hash = lambda: '1' - expected = ( - '<?xml version="1.0"?>\n' - '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n' - '<w:version>1</w:version>\n' - '<w:protocolversion>%s</w:protocolversion>\n' - '<w:capabilities>\n</w:capabilities>\n' - '</w:robot>\n') % ops.PROTOCOL_VERSION - xml = profile_robot.capabilities_xml() - self.assertStringsEqual(expected, xml) - - def testConsumerKey(self): - # setup_oauth doesn't work during testing, so heavy handed setting of - # properties it is: - self.robot._consumer_key = 'consumer' - expected = ( - '<?xml version="1.0"?>\n' - '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n' - '<w:version>1</w:version>\n' - '<w:consumer_key>consumer</w:consumer_key>\n' - '<w:protocolversion>%s</w:protocolversion>\n' - '<w:capabilities>\n</w:capabilities>\n' - '</w:robot>\n') % ops.PROTOCOL_VERSION - xml = self.robot.capabilities_xml() - self.assertStringsEqual(expected, xml) - - def testCapsAndEvents(self): - self.robot.register_handler(events.BlipSubmitted, None, - context=[events.Context.SELF, - events.Context.ROOT]) - expected = ( - '<?xml version="1.0"?>\n' - '<w:robot xmlns:w="http://wave.google.com/extensions/robots/1.0">\n' - '<w:version>1</w:version>\n' - '<w:protocolversion>%s</w:protocolversion>\n' - '<w:capabilities>\n' - ' <w:capability name="%s" context="SELF,ROOT"/>\n' - '</w:capabilities>\n' - '</w:robot>\n') % (ops.PROTOCOL_VERSION, events.BlipSubmitted.type) - xml = self.robot.capabilities_xml() - self.assertStringsEqual(expected, xml) - - -if __name__ == '__main__': - unittest.main() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/run_unit_tests.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/run_unit_tests.py b/wave/src/main/java/python/api/run_unit_tests.py deleted file mode 100644 index abb69f4..0000000 --- a/wave/src/main/java/python/api/run_unit_tests.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/python -# -# 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. - -"""Script to run all unit tests in this package.""" - - -import blip_test -import element_test -import module_test_runner -import ops_test -import robot_test -import util_test -import wavelet_test -import search_test - - -def RunUnitTests(): - """Runs all registered unit tests.""" - test_runner = module_test_runner.ModuleTestRunner() - test_runner.modules = [ - blip_test, - element_test, - ops_test, - robot_test, - util_test, - wavelet_test, - search_test, - ] - test_runner.RunAllTests() - - -if __name__ == "__main__": - RunUnitTests() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/search.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/search.py b/wave/src/main/java/python/api/search.py deleted file mode 100644 index 2167114..0000000 --- a/wave/src/main/java/python/api/search.py +++ /dev/null @@ -1,153 +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 search (results).""" - -import errors -import logging -import wavelet - -class Results(object): - """Models a set of search results. - - Search results are composed of a list of digests, query, and number of - results. - """ - - def __init__(self, json): - """Inits this results object with JSON data. - - Args: - json: JSON data dictionary from Wave server. - """ - if 'searchResults' in json: - json = json['searchResults'] - self._query = json.get('query') - self._num_results = json.get('numResults') - self._digests = [] - self._digests = [Digest(digest_data) for digest_data in json['digests']] - - @property - def query(self): - """Returns the query for this search.""" - return self._query - - @property - def num_results(self): - """Returns the number of results for this search.""" - return self._num_results - - @property - def digests(self): - """Returns a list of digests.""" - return self._digests - - def __iter__(self): - """Iterate over the list of digests.""" - return iter(self._digests) - - def serialize(self): - """Return a dict of the search results properties.""" - return {'query': self._query, - 'numResults': self._num_results, - 'digests': [digest.serialize() for digest in self._digests] - } - - -class Digest(object): - """Models a single digest. - - A digest is composed of title, wave ID, snippet, and participants. - """ - - def __init__(self, json): - """Inits this digest with JSON data. - - Args: - json: JSON data dictionary from Wave server. - """ - self._wave_id = json.get('waveId') - self._title = json.get('title') - self._snippet = json.get('snippet') - self._blip_count = int(json.get('blipCount')) - self._unread_count = int(json.get('unreadCount')) - self._last_modified = json.get('lastModified') - self._participants = wavelet.Participants(json.get('participants', []), - {}, - self._wave_id, - '', - None) - self._raw_data = json - - @property - def blip_count(self): - """Returns the number of blips in this wave.""" - return self._blip_count - - @property - def unread_count(self): - """Returns the number of unread blips in this wave.""" - return self._unread_count - - @property - def last_modified(self): - """Returns the last modified date of the wave.""" - return self._last_modified - - @property - def wave_id(self): - """Returns the digest wave id.""" - return self._wave_id - - @property - def snippet(self): - """Returns the snippet for the digest.""" - return self._snippet - - @property - def domain(self): - """Return the domain that the wave belongs to.""" - p = self._wave_id.find('!') - if p == -1: - return None - else: - return self._wave_id[:p] - - @property - def participants(self): - """Returns a set of participants on this wave.""" - return self._participants - - @property - def title(self): - return self._title - - def serialize(self): - """Return a dict of the digest properties.""" - return {'waveId': self._wave_id, - 'participants': self._participants.serialize(), - 'title': self._title, - 'snippet': self._snippet, - 'blipCount': self._blip_count, - 'unreadCount': self._unread_count, - 'lastModified': self._last_modified, - } - - def __str__(self): - return self._title http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/search_test.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/search_test.py b/wave/src/main/java/python/api/search_test.py deleted file mode 100644 index 9f70beb..0000000 --- a/wave/src/main/java/python/api/search_test.py +++ /dev/null @@ -1,79 +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 search module.""" - - -import unittest - -import search -import simplejson - -TEST_DIGEST_DATA = { - 'title': 'Title', - 'participants': ['[email protected]'], - 'waveId': 'test.com!w+g3h3im', - 'snippet': 'Best test ever', - 'blipCount': '10', - 'unreadCount': '2', - 'lastModified': '1275658457', -} - - -TEST_RESULTS_DATA = { - 'query': 'in:inbox', - 'numResults': 10, - 'digests': [ - TEST_DIGEST_DATA, - TEST_DIGEST_DATA - ]} - - -class TestResults(unittest.TestCase): - """Tests the wavelet class.""" - - def setUp(self): - self.results = search.Results(TEST_RESULTS_DATA) - - def testResultsProperties(self): - r = self.results - self.assertEquals(TEST_RESULTS_DATA['query'], r.query) - self.assertEquals(TEST_RESULTS_DATA['numResults'], r.num_results) - self.assertEquals(len(TEST_RESULTS_DATA['digests']), len(r.digests)) - - -class TestDigest(unittest.TestCase): - """Tests the wavelet class.""" - - def setUp(self): - self.digest = search.Digest(TEST_DIGEST_DATA) - - def testDigestProperties(self): - d = self.digest - self.assertEquals(TEST_DIGEST_DATA['title'], d.title) - self.assertEquals(TEST_DIGEST_DATA['waveId'], d.wave_id) - self.assertEquals(TEST_DIGEST_DATA['snippet'], d.snippet) - self.assertEquals(TEST_DIGEST_DATA['blipCount'], str(d.blip_count)) - self.assertEquals(TEST_DIGEST_DATA['unreadCount'], str(d.unread_count)) - self.assertEquals(TEST_DIGEST_DATA['lastModified'], d.last_modified) - self.assertTrue(TEST_DIGEST_DATA['participants'][0] in d.participants) - self.assertEquals('test.com', d.domain) - -if __name__ == '__main__': - unittest.main() http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/LICENSE ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/LICENSE b/wave/src/main/java/python/api/simplejson/LICENSE deleted file mode 100644 index 8676302..0000000 --- a/wave/src/main/java/python/api/simplejson/LICENSE +++ /dev/null @@ -1,19 +0,0 @@ -Copyright (c) 2006 Bob Ippolito - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies -of the Software, and to permit persons to whom the Software is furnished to do -so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/__init__.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/__init__.py b/wave/src/main/java/python/api/simplejson/__init__.py deleted file mode 100644 index a111e0c..0000000 --- a/wave/src/main/java/python/api/simplejson/__init__.py +++ /dev/null @@ -1,424 +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"""JSON (JavaScript Object Notation) <http://json.org> is a subset of -JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data -interchange format. - -:mod:`simplejson` exposes an API familiar to users of the standard library -:mod:`marshal` and :mod:`pickle` modules. It is the externally maintained -version of the :mod:`json` library contained in Python 2.6, but maintains -compatibility with Python 2.4 and Python 2.5 and (currently) has -significant performance advantages, even without using the optional C -extension for speedups. - -Encoding basic Python object hierarchies:: - - >>> import simplejson as json - >>> json.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}]) - '["foo", {"bar": ["baz", null, 1.0, 2]}]' - >>> print json.dumps("\"foo\bar") - "\"foo\bar" - >>> print json.dumps(u'\u1234') - "\u1234" - >>> print json.dumps('\\') - "\\" - >>> print json.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True) - {"a": 0, "b": 0, "c": 0} - >>> from StringIO import StringIO - >>> io = StringIO() - >>> json.dump(['streaming API'], io) - >>> io.getvalue() - '["streaming API"]' - -Compact encoding:: - - >>> import simplejson as json - >>> json.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':')) - '[1,2,3,{"4":5,"6":7}]' - -Pretty printing:: - - >>> import simplejson as json - >>> s = json.dumps({'4': 5, '6': 7}, sort_keys=True, indent=' ') - >>> print '\n'.join([l.rstrip() for l in s.splitlines()]) - { - "4": 5, - "6": 7 - } - -Decoding JSON:: - - >>> import simplejson as json - >>> obj = [u'foo', {u'bar': [u'baz', None, 1.0, 2]}] - >>> json.loads('["foo", {"bar":["baz", null, 1.0, 2]}]') == obj - True - >>> json.loads('"\\"foo\\bar"') == u'"foo\x08ar' - True - >>> from StringIO import StringIO - >>> io = StringIO('["streaming API"]') - >>> json.load(io)[0] == 'streaming API' - True - -Specializing JSON object decoding:: - - >>> import simplejson as json - >>> def as_complex(dct): - ... if '__complex__' in dct: - ... return complex(dct['real'], dct['imag']) - ... return dct - ... - >>> json.loads('{"__complex__": true, "real": 1, "imag": 2}', - ... object_hook=as_complex) - (1+2j) - >>> from decimal import Decimal - >>> json.loads('1.1', parse_float=Decimal) == Decimal('1.1') - True - -Specializing JSON object encoding:: - - >>> import simplejson as json - >>> def encode_complex(obj): - ... if isinstance(obj, complex): - ... return [obj.real, obj.imag] - ... raise TypeError(repr(o) + " is not JSON serializable") - ... - >>> json.dumps(2 + 1j, default=encode_complex) - '[2.0, 1.0]' - >>> json.JSONEncoder(default=encode_complex).encode(2 + 1j) - '[2.0, 1.0]' - >>> ''.join(json.JSONEncoder(default=encode_complex).iterencode(2 + 1j)) - '[2.0, 1.0]' - - -Using simplejson.tool from the shell to validate and pretty-print:: - - $ 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) -""" -__version__ = '2.1.0' -__all__ = [ - 'dump', 'dumps', 'load', 'loads', - 'JSONDecoder', 'JSONDecodeError', 'JSONEncoder', - 'OrderedDict', -] - -__author__ = 'Bob Ippolito <[email protected]>' - -from decoder import JSONDecoder, JSONDecodeError -from encoder import JSONEncoder -try: - from collections import OrderedDict -except ImportError: - from ordered_dict import OrderedDict - -_default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8', - default=None, -) - -def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` as a JSON formatted stream to ``fp`` (a - ``.write()``-supporting file-like object). - - If ``skipkeys`` is true then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the some chunks written to ``fp`` - may be ``unicode`` instances, subject to normal Python ``str`` to - ``unicode`` coercion rules. Unless ``fp.write()`` explicitly - understands ``unicode`` (as in ``codecs.getwriter()``) this is likely - to cause an error. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) - in strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If *indent* is a string, then JSON array elements and object members - will be pretty-printed with a newline followed by that string repeated - for each level of nesting. ``None`` (the default) selects the most compact - representation without any newlines. For backwards compatibility with - versions of simplejson earlier than 2.1.0, an integer is also accepted - and is converted to a string with that many spaces. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - iterable = _default_encoder.iterencode(obj) - else: - if cls is None: - cls = JSONEncoder - iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, - default=default, **kw).iterencode(obj) - # could accelerate with writelines in some versions of Python, at - # a debuggability cost - for chunk in iterable: - fp.write(chunk) - - -def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True, - allow_nan=True, cls=None, indent=None, separators=None, - encoding='utf-8', default=None, **kw): - """Serialize ``obj`` to a JSON formatted ``str``. - - If ``skipkeys`` is false then ``dict`` keys that are not basic types - (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``) - will be skipped instead of raising a ``TypeError``. - - If ``ensure_ascii`` is false, then the return value will be a - ``unicode`` instance subject to normal Python ``str`` to ``unicode`` - coercion rules instead of being escaped to an ASCII ``str``. - - If ``check_circular`` is false, then the circular reference check - for container types will be skipped and a circular reference will - result in an ``OverflowError`` (or worse). - - If ``allow_nan`` is false, then it will be a ``ValueError`` to - serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in - strict compliance of the JSON specification, instead of using the - JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``). - - If ``indent`` is a string, then JSON array elements and object members - will be pretty-printed with a newline followed by that string repeated - for each level of nesting. ``None`` (the default) selects the most compact - representation without any newlines. For backwards compatibility with - versions of simplejson earlier than 2.1.0, an integer is also accepted - and is converted to a string with that many spaces. - - If ``separators`` is an ``(item_separator, dict_separator)`` tuple - then it will be used instead of the default ``(', ', ': ')`` separators. - ``(',', ':')`` is the most compact JSON representation. - - ``encoding`` is the character encoding for str instances, default is UTF-8. - - ``default(obj)`` is a function that should return a serializable version - of obj or raise TypeError. The default simply raises TypeError. - - To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the - ``.default()`` method to serialize additional types), specify it with - the ``cls`` kwarg. - - """ - # cached encoder - if (not skipkeys and ensure_ascii and - check_circular and allow_nan and - cls is None and indent is None and separators is None and - encoding == 'utf-8' and default is None and not kw): - return _default_encoder.encode(obj) - if cls is None: - cls = JSONEncoder - return cls( - skipkeys=skipkeys, ensure_ascii=ensure_ascii, - check_circular=check_circular, allow_nan=allow_nan, indent=indent, - separators=separators, encoding=encoding, default=default, - **kw).encode(obj) - - -_default_decoder = JSONDecoder(encoding=None, object_hook=None, - object_pairs_hook=None) - - -def load(fp, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, object_pairs_hook=None, **kw): - """Deserialize ``fp`` (a ``.read()``-supporting file-like object containing - a JSON document) to a Python object. - - *encoding* determines the encoding used to interpret any - :class:`str` objects decoded by this instance (``'utf-8'`` by - default). It has no effect when decoding :class:`unicode` objects. - - Note that currently only encodings that are a superset of ASCII work, - strings of other encodings should be passed in as :class:`unicode`. - - *object_hook*, if specified, will be called with the result of every - JSON object decoded and its return value will be used in place of the - given :class:`dict`. This can be used to provide custom - deserializations (e.g. to support JSON-RPC class hinting). - - *object_pairs_hook* is an optional function that will be called with - the result of any object literal decode with an ordered list of pairs. - The return value of *object_pairs_hook* will be used instead of the - :class:`dict`. This feature can be used to implement custom decoders - that rely on the order that the key and value pairs are decoded (for - example, :func:`collections.OrderedDict` will remember the order of - insertion). If *object_hook* is also defined, the *object_pairs_hook* - takes priority. - - *parse_float*, if specified, will be called with the string of every - JSON float to be decoded. By default, this is equivalent to - ``float(num_str)``. This can be used to use another datatype or parser - for JSON floats (e.g. :class:`decimal.Decimal`). - - *parse_int*, if specified, will be called with the string of every - JSON int to be decoded. By default, this is equivalent to - ``int(num_str)``. This can be used to use another datatype or parser - for JSON integers (e.g. :class:`float`). - - *parse_constant*, if specified, will be called with one of the - following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This - can be used to raise an exception if invalid JSON numbers are - encountered. - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - return loads(fp.read(), - encoding=encoding, cls=cls, object_hook=object_hook, - parse_float=parse_float, parse_int=parse_int, - parse_constant=parse_constant, object_pairs_hook=object_pairs_hook, - **kw) - - -def loads(s, encoding=None, cls=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, object_pairs_hook=None, **kw): - """Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON - document) to a Python object. - - *encoding* determines the encoding used to interpret any - :class:`str` objects decoded by this instance (``'utf-8'`` by - default). It has no effect when decoding :class:`unicode` objects. - - Note that currently only encodings that are a superset of ASCII work, - strings of other encodings should be passed in as :class:`unicode`. - - *object_hook*, if specified, will be called with the result of every - JSON object decoded and its return value will be used in place of the - given :class:`dict`. This can be used to provide custom - deserializations (e.g. to support JSON-RPC class hinting). - - *object_pairs_hook* is an optional function that will be called with - the result of any object literal decode with an ordered list of pairs. - The return value of *object_pairs_hook* will be used instead of the - :class:`dict`. This feature can be used to implement custom decoders - that rely on the order that the key and value pairs are decoded (for - example, :func:`collections.OrderedDict` will remember the order of - insertion). If *object_hook* is also defined, the *object_pairs_hook* - takes priority. - - *parse_float*, if specified, will be called with the string of every - JSON float to be decoded. By default, this is equivalent to - ``float(num_str)``. This can be used to use another datatype or parser - for JSON floats (e.g. :class:`decimal.Decimal`). - - *parse_int*, if specified, will be called with the string of every - JSON int to be decoded. By default, this is equivalent to - ``int(num_str)``. This can be used to use another datatype or parser - for JSON integers (e.g. :class:`float`). - - *parse_constant*, if specified, will be called with one of the - following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This - can be used to raise an exception if invalid JSON numbers are - encountered. - - To use a custom ``JSONDecoder`` subclass, specify it with the ``cls`` - kwarg. - - """ - if (cls is None and encoding is None and object_hook is None and - parse_int is None and parse_float is None and - parse_constant is None and object_pairs_hook is None and not kw): - return _default_decoder.decode(s) - if cls is None: - cls = JSONDecoder - if object_hook is not None: - kw['object_hook'] = object_hook - if object_pairs_hook is not None: - kw['object_pairs_hook'] = object_pairs_hook - if parse_float is not None: - kw['parse_float'] = parse_float - if parse_int is not None: - kw['parse_int'] = parse_int - if parse_constant is not None: - kw['parse_constant'] = parse_constant - return cls(encoding=encoding, **kw).decode(s) - - -def _toggle_speedups(enabled): - import simplejson.decoder as dec - import simplejson.encoder as enc - import simplejson.scanner as scan - try: - from simplejson._speedups import make_encoder as c_make_encoder - except ImportError: - c_make_encoder = None - if enabled: - dec.scanstring = dec.c_scanstring or dec.py_scanstring - enc.c_make_encoder = c_make_encoder - enc.encode_basestring_ascii = (enc.c_encode_basestring_ascii or - enc.py_encode_basestring_ascii) - scan.make_scanner = scan.c_make_scanner or scan.py_make_scanner - else: - dec.scanstring = dec.py_scanstring - enc.c_make_encoder = None - enc.encode_basestring_ascii = enc.py_encode_basestring_ascii - scan.make_scanner = scan.py_make_scanner - dec.make_scanner = scan.make_scanner - global _default_decoder - _default_decoder = JSONDecoder( - encoding=None, - object_hook=None, - object_pairs_hook=None, - ) - global _default_encoder - _default_encoder = JSONEncoder( - skipkeys=False, - ensure_ascii=True, - check_circular=True, - allow_nan=True, - indent=None, - separators=None, - encoding='utf-8', - default=None, - ) http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/decoder.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/decoder.py b/wave/src/main/java/python/api/simplejson/decoder.py deleted file mode 100644 index 95e4f5f..0000000 --- a/wave/src/main/java/python/api/simplejson/decoder.py +++ /dev/null @@ -1,431 +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. -# -# -"""Implementation of JSONDecoder -""" -import re -import sys -import struct - -from scanner import make_scanner -try: - from _speedups import scanstring as c_scanstring -except ImportError: - c_scanstring = None - -__all__ = ['JSONDecoder'] - -FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL - -def _floatconstants(): - _BYTES = '7FF80000000000007FF0000000000000'.decode('hex') - # The struct module in Python 2.4 would get frexp() out of range here - # when an endian is specified in the format string. Fixed in Python 2.5+ - if sys.byteorder != 'big': - _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1] - nan, inf = struct.unpack('dd', _BYTES) - return nan, inf, -inf - -NaN, PosInf, NegInf = _floatconstants() - - -class JSONDecodeError(ValueError): - """Subclass of ValueError with the following additional properties: - - msg: The unformatted error message - doc: The JSON document being parsed - pos: The start index of doc where parsing failed - end: The end index of doc where parsing failed (may be None) - lineno: The line corresponding to pos - colno: The column corresponding to pos - endlineno: The line corresponding to end (may be None) - endcolno: The column corresponding to end (may be None) - - """ - def __init__(self, msg, doc, pos, end=None): - ValueError.__init__(self, errmsg(msg, doc, pos, end=end)) - self.msg = msg - self.doc = doc - self.pos = pos - self.end = end - self.lineno, self.colno = linecol(doc, pos) - if end is not None: - self.endlineno, self.endcolno = linecol(doc, pos) - else: - self.endlineno, self.endcolno = None, None - - -def linecol(doc, pos): - lineno = doc.count('\n', 0, pos) + 1 - if lineno == 1: - colno = pos - else: - colno = pos - doc.rindex('\n', 0, pos) - return lineno, colno - - -def errmsg(msg, doc, pos, end=None): - # Note that this function is called from _speedups - lineno, colno = linecol(doc, pos) - if end is None: - #fmt = '{0}: line {1} column {2} (char {3})' - #return fmt.format(msg, lineno, colno, pos) - fmt = '%s: line %d column %d (char %d)' - return fmt % (msg, lineno, colno, pos) - endlineno, endcolno = linecol(doc, end) - #fmt = '{0}: line {1} column {2} - line {3} column {4} (char {5} - {6})' - #return fmt.format(msg, lineno, colno, endlineno, endcolno, pos, end) - fmt = '%s: line %d column %d - line %d column %d (char %d - %d)' - return fmt % (msg, lineno, colno, endlineno, endcolno, pos, end) - - -_CONSTANTS = { - '-Infinity': NegInf, - 'Infinity': PosInf, - 'NaN': NaN, -} - -STRINGCHUNK = re.compile(r'(.*?)(["\\\x00-\x1f])', FLAGS) -BACKSLASH = { - '"': u'"', '\\': u'\\', '/': u'/', - 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t', -} - -DEFAULT_ENCODING = "utf-8" - -def py_scanstring(s, end, encoding=None, strict=True, - _b=BACKSLASH, _m=STRINGCHUNK.match): - """Scan the string s for a JSON string. End is the index of the - character in s after the quote that started the JSON string. - Unescapes all valid JSON string escape sequences and raises ValueError - on attempt to decode an invalid string. If strict is False then literal - control characters are allowed in the string. - - Returns a tuple of the decoded string and the index of the character in s - after the end quote.""" - if encoding is None: - encoding = DEFAULT_ENCODING - chunks = [] - _append = chunks.append - begin = end - 1 - while 1: - chunk = _m(s, end) - if chunk is None: - raise JSONDecodeError( - "Unterminated string starting at", s, begin) - end = chunk.end() - content, terminator = chunk.groups() - # Content is contains zero or more unescaped string characters - if content: - if not isinstance(content, unicode): - content = unicode(content, encoding) - _append(content) - # Terminator is the end of string, a literal control character, - # or a backslash denoting that an escape sequence follows - if terminator == '"': - break - elif terminator != '\\': - if strict: - msg = "Invalid control character %r at" % (terminator,) - #msg = "Invalid control character {0!r} at".format(terminator) - raise JSONDecodeError(msg, s, end) - else: - _append(terminator) - continue - try: - esc = s[end] - except IndexError: - raise JSONDecodeError( - "Unterminated string starting at", s, begin) - # If not a unicode escape sequence, must be in the lookup table - if esc != 'u': - try: - char = _b[esc] - except KeyError: - msg = "Invalid \\escape: " + repr(esc) - raise JSONDecodeError(msg, s, end) - end += 1 - else: - # Unicode escape sequence - esc = s[end + 1:end + 5] - next_end = end + 5 - if len(esc) != 4: - msg = "Invalid \\uXXXX escape" - raise JSONDecodeError(msg, s, end) - uni = int(esc, 16) - # Check for surrogate pair on UCS-4 systems - if 0xd800 <= uni <= 0xdbff and sys.maxunicode > 65535: - msg = "Invalid \\uXXXX\\uXXXX surrogate pair" - if not s[end + 5:end + 7] == '\\u': - raise JSONDecodeError(msg, s, end) - esc2 = s[end + 7:end + 11] - if len(esc2) != 4: - raise JSONDecodeError(msg, s, end) - uni2 = int(esc2, 16) - uni = 0x10000 + (((uni - 0xd800) << 10) | (uni2 - 0xdc00)) - next_end += 6 - char = unichr(uni) - end = next_end - # Append the unescaped character - _append(char) - return u''.join(chunks), end - - -# Use speedup if available -scanstring = c_scanstring or py_scanstring - -WHITESPACE = re.compile(r'[ \t\n\r]*', FLAGS) -WHITESPACE_STR = ' \t\n\r' - -def JSONObject((s, end), encoding, strict, scan_once, object_hook, - object_pairs_hook, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - pairs = [] - # Use a slice to prevent IndexError from being raised, the following - # check will raise a more specific ValueError if the string is empty - nextchar = s[end:end + 1] - # Normally we expect nextchar == '"' - if nextchar != '"': - if nextchar in _ws: - end = _w(s, end).end() - nextchar = s[end:end + 1] - # Trivial empty object - if nextchar == '}': - if object_pairs_hook is not None: - result = object_pairs_hook(pairs) - return result, end - pairs = {} - if object_hook is not None: - pairs = object_hook(pairs) - return pairs, end + 1 - elif nextchar != '"': - raise JSONDecodeError("Expecting property name", s, end) - end += 1 - while True: - key, end = scanstring(s, end, encoding, strict) - - # To skip some function call overhead we optimize the fast paths where - # the JSON key separator is ": " or just ":". - if s[end:end + 1] != ':': - end = _w(s, end).end() - if s[end:end + 1] != ':': - raise JSONDecodeError("Expecting : delimiter", s, end) - - end += 1 - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - try: - value, end = scan_once(s, end) - except StopIteration: - raise JSONDecodeError("Expecting object", s, end) - pairs.append((key, value)) - - try: - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - end += 1 - - if nextchar == '}': - break - elif nextchar != ',': - raise JSONDecodeError("Expecting , delimiter", s, end - 1) - - try: - nextchar = s[end] - if nextchar in _ws: - end += 1 - nextchar = s[end] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end] - except IndexError: - nextchar = '' - - end += 1 - if nextchar != '"': - raise JSONDecodeError("Expecting property name", s, end - 1) - - if object_pairs_hook is not None: - result = object_pairs_hook(pairs) - return result, end - pairs = dict(pairs) - if object_hook is not None: - pairs = object_hook(pairs) - return pairs, end - -def JSONArray((s, end), scan_once, _w=WHITESPACE.match, _ws=WHITESPACE_STR): - values = [] - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - # Look-ahead for trivial empty array - if nextchar == ']': - return values, end + 1 - _append = values.append - while True: - try: - value, end = scan_once(s, end) - except StopIteration: - raise JSONDecodeError("Expecting object", s, end) - _append(value) - nextchar = s[end:end + 1] - if nextchar in _ws: - end = _w(s, end + 1).end() - nextchar = s[end:end + 1] - end += 1 - if nextchar == ']': - break - elif nextchar != ',': - raise JSONDecodeError("Expecting , delimiter", s, end) - - try: - if s[end] in _ws: - end += 1 - if s[end] in _ws: - end = _w(s, end + 1).end() - except IndexError: - pass - - return values, end - -class JSONDecoder(object): - """Simple JSON <http://json.org> decoder - - Performs the following translations in decoding by default: - - +---------------+-------------------+ - | JSON | Python | - +===============+===================+ - | object | dict | - +---------------+-------------------+ - | array | list | - +---------------+-------------------+ - | string | unicode | - +---------------+-------------------+ - | number (int) | int, long | - +---------------+-------------------+ - | number (real) | float | - +---------------+-------------------+ - | true | True | - +---------------+-------------------+ - | false | False | - +---------------+-------------------+ - | null | None | - +---------------+-------------------+ - - It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as - their corresponding ``float`` values, which is outside the JSON spec. - - """ - - def __init__(self, encoding=None, object_hook=None, parse_float=None, - parse_int=None, parse_constant=None, strict=True, - object_pairs_hook=None): - """ - *encoding* determines the encoding used to interpret any - :class:`str` objects decoded by this instance (``'utf-8'`` by - default). It has no effect when decoding :class:`unicode` objects. - - Note that currently only encodings that are a superset of ASCII work, - strings of other encodings should be passed in as :class:`unicode`. - - *object_hook*, if specified, will be called with the result of every - JSON object decoded and its return value will be used in place of the - given :class:`dict`. This can be used to provide custom - deserializations (e.g. to support JSON-RPC class hinting). - - *object_pairs_hook* is an optional function that will be called with - the result of any object literal decode with an ordered list of pairs. - The return value of *object_pairs_hook* will be used instead of the - :class:`dict`. This feature can be used to implement custom decoders - that rely on the order that the key and value pairs are decoded (for - example, :func:`collections.OrderedDict` will remember the order of - insertion). If *object_hook* is also defined, the *object_pairs_hook* - takes priority. - - *parse_float*, if specified, will be called with the string of every - JSON float to be decoded. By default, this is equivalent to - ``float(num_str)``. This can be used to use another datatype or parser - for JSON floats (e.g. :class:`decimal.Decimal`). - - *parse_int*, if specified, will be called with the string of every - JSON int to be decoded. By default, this is equivalent to - ``int(num_str)``. This can be used to use another datatype or parser - for JSON integers (e.g. :class:`float`). - - *parse_constant*, if specified, will be called with one of the - following strings: ``'-Infinity'``, ``'Infinity'``, ``'NaN'``. This - can be used to raise an exception if invalid JSON numbers are - encountered. - - *strict* controls the parser's behavior when it encounters an - invalid control character in a string. The default setting of - ``True`` means that unescaped control characters are parse errors, if - ``False`` then control characters will be allowed in strings. - - """ - self.encoding = encoding - self.object_hook = object_hook - self.object_pairs_hook = object_pairs_hook - self.parse_float = parse_float or float - self.parse_int = parse_int or int - self.parse_constant = parse_constant or _CONSTANTS.__getitem__ - self.strict = strict - self.parse_object = JSONObject - self.parse_array = JSONArray - self.parse_string = scanstring - self.scan_once = make_scanner(self) - - def decode(self, s, _w=WHITESPACE.match): - """Return the Python representation of ``s`` (a ``str`` or ``unicode`` - instance containing a JSON document) - - """ - obj, end = self.raw_decode(s, idx=_w(s, 0).end()) - end = _w(s, end).end() - if end != len(s): - raise JSONDecodeError("Extra data", s, end, len(s)) - return obj - - def raw_decode(self, s, idx=0): - """Decode a JSON document from ``s`` (a ``str`` or ``unicode`` - beginning with a JSON document) and return a 2-tuple of the Python - representation and the index in ``s`` where the document ended. - - This can be used to decode a JSON document from a string that may - have extraneous data at the end. - - """ - try: - obj, end = self.scan_once(s, idx) - except StopIteration: - raise JSONDecodeError("No JSON object could be decoded", s, idx) - return obj, end http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/78cbf78f/wave/src/main/java/python/api/simplejson/encoder.py ---------------------------------------------------------------------- diff --git a/wave/src/main/java/python/api/simplejson/encoder.py b/wave/src/main/java/python/api/simplejson/encoder.py deleted file mode 100644 index 1ddf35c..0000000 --- a/wave/src/main/java/python/api/simplejson/encoder.py +++ /dev/null @@ -1,476 +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. -# -# -"""Implementation of JSONEncoder -""" -import re - -try: - from _speedups import encode_basestring_ascii as \ - c_encode_basestring_ascii -except ImportError: - c_encode_basestring_ascii = None -try: - from _speedups import make_encoder as c_make_encoder -except ImportError: - c_make_encoder = None - -from decoder import PosInf - -ESCAPE = re.compile(r'[\x00-\x1f\\"\b\f\n\r\t]') -ESCAPE_ASCII = re.compile(r'([\\"]|[^\ -~])') -HAS_UTF8 = re.compile(r'[\x80-\xff]') -ESCAPE_DCT = { - '\\': '\\\\', - '"': '\\"', - '\b': '\\b', - '\f': '\\f', - '\n': '\\n', - '\r': '\\r', - '\t': '\\t', -} -for i in range(0x20): - #ESCAPE_DCT.setdefault(chr(i), '\\u{0:04x}'.format(i)) - ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,)) - -FLOAT_REPR = repr - -def encode_basestring(s): - """Return a JSON representation of a Python string - - """ - if isinstance(s, str) and HAS_UTF8.search(s) is not None: - s = s.decode('utf-8') - def replace(match): - return ESCAPE_DCT[match.group(0)] - return u'"' + ESCAPE.sub(replace, s) + u'"' - - -def py_encode_basestring_ascii(s): - """Return an ASCII-only JSON representation of a Python string - - """ - if isinstance(s, str) and HAS_UTF8.search(s) is not None: - s = s.decode('utf-8') - def replace(match): - s = match.group(0) - try: - return ESCAPE_DCT[s] - except KeyError: - n = ord(s) - if n < 0x10000: - #return '\\u{0:04x}'.format(n) - return '\\u%04x' % (n,) - else: - # surrogate pair - n -= 0x10000 - s1 = 0xd800 | ((n >> 10) & 0x3ff) - s2 = 0xdc00 | (n & 0x3ff) - #return '\\u{0:04x}\\u{1:04x}'.format(s1, s2) - return '\\u%04x\\u%04x' % (s1, s2) - return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"' - - -encode_basestring_ascii = ( - c_encode_basestring_ascii or py_encode_basestring_ascii) - -class JSONEncoder(object): - """Extensible JSON <http://json.org> encoder for Python data structures. - - Supports the following objects and types by default: - - +-------------------+---------------+ - | Python | JSON | - +===================+===============+ - | dict | object | - +-------------------+---------------+ - | list, tuple | array | - +-------------------+---------------+ - | str, unicode | string | - +-------------------+---------------+ - | int, long, float | number | - +-------------------+---------------+ - | True | true | - +-------------------+---------------+ - | False | false | - +-------------------+---------------+ - | None | null | - +-------------------+---------------+ - - To extend this to recognize other objects, subclass and implement a - ``.default()`` method with another method that returns a serializable - object for ``o`` if possible, otherwise it should call the superclass - implementation (to raise ``TypeError``). - - """ - item_separator = ', ' - key_separator = ': ' - def __init__(self, skipkeys=False, ensure_ascii=True, - check_circular=True, allow_nan=True, sort_keys=False, - indent=None, separators=None, encoding='utf-8', default=None): - """Constructor for JSONEncoder, with sensible defaults. - - If skipkeys is false, then it is a TypeError to attempt - encoding of keys that are not str, int, long, float or None. If - skipkeys is True, such items are simply skipped. - - If ensure_ascii is true, the output is guaranteed to be str - objects with all incoming unicode characters escaped. If - ensure_ascii is false, the output will be unicode object. - - If check_circular is true, then lists, dicts, and custom encoded - objects will be checked for circular references during encoding to - prevent an infinite recursion (which would cause an OverflowError). - Otherwise, no such check takes place. - - If allow_nan is true, then NaN, Infinity, and -Infinity will be - encoded as such. This behavior is not JSON specification compliant, - but is consistent with most JavaScript based encoders and decoders. - Otherwise, it will be a ValueError to encode such floats. - - If sort_keys is true, then the output of dictionaries will be - sorted by key; this is useful for regression tests to ensure - that JSON serializations can be compared on a day-to-day basis. - - If indent is a string, then JSON array elements and object members - will be pretty-printed with a newline followed by that string repeated - for each level of nesting. ``None`` (the default) selects the most compact - representation without any newlines. For backwards compatibility with - versions of simplejson earlier than 2.1.0, an integer is also accepted - and is converted to a string with that many spaces. - - If specified, separators should be a (item_separator, key_separator) - tuple. The default is (', ', ': '). To get the most compact JSON - representation you should specify (',', ':') to eliminate whitespace. - - If specified, default is a function that gets called for objects - that can't otherwise be serialized. It should return a JSON encodable - version of the object or raise a ``TypeError``. - - If encoding is not None, then all input strings will be - transformed into unicode using that encoding prior to JSON-encoding. - The default is UTF-8. - - """ - - self.skipkeys = skipkeys - self.ensure_ascii = ensure_ascii - self.check_circular = check_circular - self.allow_nan = allow_nan - self.sort_keys = sort_keys - if isinstance(indent, (int, long)): - indent = ' ' * indent - self.indent = indent - if separators is not None: - self.item_separator, self.key_separator = separators - if default is not None: - self.default = default - self.encoding = encoding - - def default(self, o): - """Implement this method in a subclass such that it returns - a serializable object for ``o``, or calls the base implementation - (to raise a ``TypeError``). - - For example, to support arbitrary iterators, you could - implement default like this:: - - def default(self, o): - try: - iterable = iter(o) - except TypeError: - pass - else: - return list(iterable) - return JSONEncoder.default(self, o) - - """ - raise TypeError(repr(o) + " is not JSON serializable") - - def encode(self, o): - """Return a JSON string representation of a Python data structure. - - >>> from simplejson import JSONEncoder - >>> JSONEncoder().encode({"foo": ["bar", "baz"]}) - '{"foo": ["bar", "baz"]}' - - """ - # This is for extremely simple cases and benchmarks. - if isinstance(o, basestring): - if isinstance(o, str): - _encoding = self.encoding - if (_encoding is not None - and not (_encoding == 'utf-8')): - o = o.decode(_encoding) - if self.ensure_ascii: - return encode_basestring_ascii(o) - else: - return encode_basestring(o) - # This doesn't pass the iterator directly to ''.join() because the - # exceptions aren't as detailed. The list call should be roughly - # equivalent to the PySequence_Fast that ''.join() would do. - chunks = self.iterencode(o, _one_shot=True) - if not isinstance(chunks, (list, tuple)): - chunks = list(chunks) - if self.ensure_ascii: - return ''.join(chunks) - else: - return u''.join(chunks) - - def iterencode(self, o, _one_shot=False): - """Encode the given object and yield each string - representation as available. - - For example:: - - for chunk in JSONEncoder().iterencode(bigobject): - mysocket.write(chunk) - - """ - if self.check_circular: - markers = {} - else: - markers = None - if self.ensure_ascii: - _encoder = encode_basestring_ascii - else: - _encoder = encode_basestring - if self.encoding != 'utf-8': - def _encoder(o, _orig_encoder=_encoder, _encoding=self.encoding): - if isinstance(o, str): - o = o.decode(_encoding) - return _orig_encoder(o) - - def floatstr(o, allow_nan=self.allow_nan, - _repr=FLOAT_REPR, _inf=PosInf, _neginf=-PosInf): - # Check for specials. Note that this type of test is processor - # and/or platform-specific, so do tests which don't depend on - # the internals. - - if o != o: - text = 'NaN' - elif o == _inf: - text = 'Infinity' - elif o == _neginf: - text = '-Infinity' - else: - return _repr(o) - - if not allow_nan: - raise ValueError( - "Out of range float values are not JSON compliant: " + - repr(o)) - - return text - - - if (_one_shot and c_make_encoder is not None - and not self.indent and not self.sort_keys): - _iterencode = c_make_encoder( - markers, self.default, _encoder, self.indent, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, self.allow_nan) - else: - _iterencode = _make_iterencode( - markers, self.default, _encoder, self.indent, floatstr, - self.key_separator, self.item_separator, self.sort_keys, - self.skipkeys, _one_shot) - return _iterencode(o, 0) - -def _make_iterencode(markers, _default, _encoder, _indent, _floatstr, - _key_separator, _item_separator, _sort_keys, _skipkeys, _one_shot, - ## HACK: hand-optimized bytecode; turn globals into locals - False=False, - True=True, - ValueError=ValueError, - basestring=basestring, - dict=dict, - float=float, - id=id, - int=int, - isinstance=isinstance, - list=list, - long=long, - str=str, - tuple=tuple, - ): - - def _iterencode_list(lst, _current_indent_level): - if not lst: - yield '[]' - return - if markers is not None: - markerid = id(lst) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = lst - buf = '[' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (_indent * _current_indent_level) - separator = _item_separator + newline_indent - buf += newline_indent - else: - newline_indent = None - separator = _item_separator - first = True - for value in lst: - if first: - first = False - else: - buf = separator - if isinstance(value, basestring): - yield buf + _encoder(value) - elif value is None: - yield buf + 'null' - elif value is True: - yield buf + 'true' - elif value is False: - yield buf + 'false' - elif isinstance(value, (int, long)): - yield buf + str(value) - elif isinstance(value, float): - yield buf + _floatstr(value) - else: - yield buf - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (_indent * _current_indent_level) - yield ']' - if markers is not None: - del markers[markerid] - - def _iterencode_dict(dct, _current_indent_level): - if not dct: - yield '{}' - return - if markers is not None: - markerid = id(dct) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = dct - yield '{' - if _indent is not None: - _current_indent_level += 1 - newline_indent = '\n' + (_indent * _current_indent_level) - item_separator = _item_separator + newline_indent - yield newline_indent - else: - newline_indent = None - item_separator = _item_separator - first = True - if _sort_keys: - items = dct.items() - items.sort(key=lambda kv: kv[0]) - else: - items = dct.iteritems() - for key, value in items: - if isinstance(key, basestring): - pass - # JavaScript is weakly typed for these, so it makes sense to - # also allow them. Many encoders seem to do something like this. - elif isinstance(key, float): - key = _floatstr(key) - elif key is True: - key = 'true' - elif key is False: - key = 'false' - elif key is None: - key = 'null' - elif isinstance(key, (int, long)): - key = str(key) - elif _skipkeys: - continue - else: - raise TypeError("key " + repr(key) + " is not a string") - if first: - first = False - else: - yield item_separator - yield _encoder(key) - yield _key_separator - if isinstance(value, basestring): - yield _encoder(value) - elif value is None: - yield 'null' - elif value is True: - yield 'true' - elif value is False: - yield 'false' - elif isinstance(value, (int, long)): - yield str(value) - elif isinstance(value, float): - yield _floatstr(value) - else: - if isinstance(value, (list, tuple)): - chunks = _iterencode_list(value, _current_indent_level) - elif isinstance(value, dict): - chunks = _iterencode_dict(value, _current_indent_level) - else: - chunks = _iterencode(value, _current_indent_level) - for chunk in chunks: - yield chunk - if newline_indent is not None: - _current_indent_level -= 1 - yield '\n' + (_indent * _current_indent_level) - yield '}' - if markers is not None: - del markers[markerid] - - def _iterencode(o, _current_indent_level): - if isinstance(o, basestring): - yield _encoder(o) - elif o is None: - yield 'null' - elif o is True: - yield 'true' - elif o is False: - yield 'false' - elif isinstance(o, (int, long)): - yield str(o) - elif isinstance(o, float): - yield _floatstr(o) - elif isinstance(o, (list, tuple)): - for chunk in _iterencode_list(o, _current_indent_level): - yield chunk - elif isinstance(o, dict): - for chunk in _iterencode_dict(o, _current_indent_level): - yield chunk - else: - if markers is not None: - markerid = id(o) - if markerid in markers: - raise ValueError("Circular reference detected") - markers[markerid] = o - o = _default(o) - for chunk in _iterencode(o, _current_indent_level): - yield chunk - if markers is not None: - del markers[markerid] - - return _iterencode
