Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge Python 3 support! Closes #81.

  • Loading branch information...
commit bd42d2caada5707a0ad258c568293fe1df9b68ab 2 parents 8face2e + 349bc2e
@erikrose erikrose authored
View
2  .travis.yml
@@ -5,10 +5,10 @@ services: elasticsearch
python:
- 2.6
- 2.7
+ - 3.3
- pypy
install:
- pip install -e .
- - pip install simplejson mock
script: python setup.py test
View
2  MANIFEST.in
@@ -1,7 +1,7 @@
include LICENSE
include README.rst
include AUTHORS
-include .tox.ini
+include tox.ini
include docs/Makefile
include docs/make.bat
include docs/source/*.rst
View
34 pyelasticsearch/client.py
@@ -5,7 +5,15 @@
from functools import wraps
from logging import getLogger
import re
-from urllib import urlencode, quote_plus
+from six import iterkeys, string_types, integer_types, iteritems, PY3
+from six.moves import xrange
+
+try:
+ # PY3
+ from urllib.parse import urlencode, quote_plus
+except ImportError:
+ # PY2
+ from urllib import urlencode, quote_plus
import requests
import simplejson as json # for use_decimal
@@ -82,7 +90,7 @@ def decorate(*args, **kwargs):
# Make kwargs the map of normal kwargs and query_params the map of
# kwargs destined for query string params:
query_params = {}
- for k, v in kwargs.items(): # NOT iteritems; we mutate kwargs
+ for k in list(iterkeys(kwargs)): # Make a copy; we mutate kwargs.
if k.startswith('es_'):
query_params[k[3:]] = kwargs.pop(k)
elif k in convertible_args:
@@ -111,7 +119,7 @@ def __init__(self, urls, timeout=60, max_retries=0, revival_delay=300):
:arg revival_delay: Number of seconds for which to avoid a server after
it times out or is uncontactable
"""
- if isinstance(urls, basestring):
+ if isinstance(urls, string_types):
urls = [urls]
urls = [u.rstrip('/') for u in urls]
self.servers = DowntimePronePool(urls, revival_delay)
@@ -140,7 +148,7 @@ def _concat(self, items):
# TODO: Why strip out _all?
if items is None:
return ''
- if isinstance(items, basestring):
+ if isinstance(items, string_types):
items = [items]
return ','.join(i for i in items if i != '_all')
@@ -148,12 +156,14 @@ def _concat(self, items):
def _to_query(cls, obj):
"""Convert a native-Python object to a query string representation."""
# Quick and dirty thus far
- if isinstance(obj, basestring):
+ if isinstance(obj, string_types):
return obj
if isinstance(obj, bool):
return 'true' if obj else 'false'
- if isinstance(obj, (long, int, float)):
+ if isinstance(obj, integer_types):
return str(obj)
+ if isinstance(obj, float):
+ return repr(obj) # str loses precision.
if isinstance(obj, (list, tuple)):
return ','.join(cls._to_query(o) for o in obj)
iso = _iso_datetime(obj)
@@ -200,7 +210,7 @@ def send_request(self,
if query_params:
path = '?'.join(
[path, urlencode(dict((k, self._to_query(v)) for k, v in
- query_params.iteritems()))])
+ iteritems(query_params)))])
request_body = self._encode_json(body) if encode_body else body
req_method = getattr(self.session, method.lower())
@@ -483,7 +493,7 @@ def update(self, index, doc_type, id, script=None, params=None, lang=None,
def _search_or_count(self, kind, query, index=None, doc_type=None,
query_params=None):
- if isinstance(query, basestring):
+ if isinstance(query, string_types):
query_params['q'] = query
body = ''
else:
@@ -892,7 +902,7 @@ def from_python(self, value):
iso = _iso_datetime(value)
if iso:
return iso
- if isinstance(value, str):
+ if not PY3 and isinstance(value, str):
return unicode(value, errors='replace') # TODO: Be stricter.
if isinstance(value, set):
return list(value)
@@ -901,10 +911,10 @@ def from_python(self, value):
def to_python(self, value):
"""Convert values from ElasticSearch to native Python values."""
- if isinstance(value, (int, float, long, complex, list, tuple, bool)):
+ if isinstance(value, (float, complex, list, tuple, bool) + integer_types):
return value
- if isinstance(value, basestring):
+ if isinstance(value, string_types):
possible_datetime = DATETIME_REGEX.search(value)
if possible_datetime:
@@ -926,7 +936,7 @@ def to_python(self, value):
# Try to handle most built-in types.
if isinstance(
converted_value,
- (list, tuple, set, dict, int, float, long, complex)):
+ (list, tuple, set, dict, float, complex) + integer_types):
return converted_value
except Exception:
# If it fails (SyntaxError or its ilk) or we don't trust it,
View
17 pyelasticsearch/tests.py
@@ -2,9 +2,11 @@
"""
Unit tests for pyelasticsearch. These require an elasticsearch server running on the default port (localhost:9200).
"""
+import sys
from datetime import datetime, date
from decimal import Decimal
import unittest
+import six
from mock import patch
import requests
@@ -16,7 +18,8 @@
def arbitrary_response():
response = requests.Response()
- response._content = '{"some": "json"}'
+ response._content = six.b('{"some": "json"}')
+ response.status_code = 200
return response
@@ -235,7 +238,7 @@ def testErrorHandling(self):
# Test invalid JSON.
self.assertRaises(ValueError, conn._encode_json, object())
resp = requests.Response()
- resp._content = '{"busted" "json" "that": ["is] " wrong'
+ resp._content = six.b('{"busted" "json" "that": ["is] " wrong')
self.assertRaises(InvalidJsonResponseError, conn._decode_response, resp)
def testUpdate(self):
@@ -493,7 +496,7 @@ def test_death_and_rebirth(self):
session_get.side_effect = Timeout
# This should kill off both servers:
- for x in xrange(2):
+ for x in range(2):
try:
conn.get('test-index', 'test-type', 7)
except Timeout:
@@ -530,7 +533,6 @@ def test_to_query(self):
"""Test the thing that translates objects to query string text."""
to_query = ElasticSearch._to_query
self.assertEqual(to_query(4), '4')
- self.assertEqual(to_query(4L), '4')
self.assertEqual(to_query(4.5), '4.5')
self.assertEqual(to_query(True), 'true')
self.assertEqual(to_query(('4', 'hi', 'thomas')), '4,hi,thomas')
@@ -540,6 +542,11 @@ def test_to_query(self):
'2000-01-02T00:00:00')
self.assertRaises(TypeError, to_query, object())
+ # do not use unittest.skipIf because of python 2.6
+ if not six.PY3:
+ self.assertEqual(to_query(long(4)), '4')
+
+
def test_es_kwargs(self):
"""
Make sure ``es_kwargs`` bundles es_ and specifically called out kwargs
@@ -563,7 +570,7 @@ def test_index(self):
def valid_responder(*args, **kwargs):
"""Return an arbitrary successful Response."""
response = requests.Response()
- response._content = '{"some": "json"}'
+ response._content = six.b('{"some": "json"}')
response.status_code = 200
return response
View
19 setup.py
@@ -1,16 +1,15 @@
import codecs
-import os
import re
+from os.path import join, dirname
from setuptools import setup, find_packages
-def read(*parts):
- return codecs.open(os.path.join(os.path.dirname(__file__), *parts)).read()
+def read(filename):
+ return codecs.open(join(dirname(__file__), filename), 'r').read()
-
-def find_version(*file_paths):
- version_file = read(*file_paths)
+def find_version(file_path):
+ version_file = read(file_path)
version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
version_file, re.M)
if version_match:
@@ -20,10 +19,10 @@ def find_version(*file_paths):
setup(
name="pyelasticsearch",
- version=find_version("pyelasticsearch/__init__.py"),
+ version=find_version(join("pyelasticsearch", "__init__.py")),
description="Lightweight python wrapper for elasticsearch.",
long_description=read('README.rst') + '\n\n' +
- '\n'.join(read('docs', 'source', 'changelog.rst')
+ '\n'.join(read(join('docs', 'source', 'changelog.rst'))
.splitlines()[1:]),
author='Robert Eanes',
author_email='python@robsinbox.com',
@@ -42,13 +41,17 @@ def find_version(*file_paths):
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 2.6',
'Programming Language :: Python :: 2.7',
+ 'Programming Language :: Python :: 3',
+ 'Programming Language :: Python :: 3.3',
'Topic :: Internet :: WWW/HTTP :: Indexing/Search'
],
requires=[ # Needed?
+ 'six',
'requests(>=1.0,<2.0)',
'simplejson(>=2.1.0)'
],
install_requires=[
+ 'six',
'requests>=1.0,<2.0',
'simplejson>=2.1.0'
],
View
2  tox.ini
@@ -4,7 +4,7 @@
# and then run "tox" from this directory.
[tox]
-envlist = py26, py27, pypy
+envlist = py26, py27, py33, pypy
[testenv]
commands = python setup.py test
Please sign in to comment.
Something went wrong with that request. Please try again.