Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .github/workflows/tox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@ jobs:
tox:
strategy:
fail-fast: false
max-parallel: 5
matrix:
python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"]
python: ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
Expand Down
2 changes: 1 addition & 1 deletion Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ requests = "*"
kazoo = "*"

[requires]
python_version = "3.9"
python_version = "3.10"
379 changes: 225 additions & 154 deletions Pipfile.lock

Large diffs are not rendered by default.

7 changes: 2 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ Features
Requirements
============

* A supported version of Python 3
* Requests 2.9.1+
* Python 3.10+
* Requests 2.32.5+
* **Optional** - ``simplejson``
* **Optional** - ``kazoo`` for SolrCloud mode

Expand All @@ -52,9 +52,6 @@ Basic usage looks like:

.. code-block:: python
# If on Python 2.X
from __future__ import print_function
import pysolr
# Create a client instance. The timeout and authentication options are not required.
Expand Down
14 changes: 1 addition & 13 deletions get-solr-download-url.py
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
#!/usr/bin/env python
# encoding: utf-8

from __future__ import absolute_import, division, print_function, unicode_literals

import sys
from itertools import chain
from urllib.parse import urljoin

import requests

# Try to import urllib from the Python 3 reorganized stdlib first:
try:
from urllib.parse import urljoin
except ImportError:
try:
from urlparse.parse import urljoin
except ImportError:
from urlparse import urljoin


if len(sys.argv) != 2:
print("Usage: %s SOLR_VERSION" % sys.argv[0], file=sys.stderr)
sys.exit(1)
Expand Down
163 changes: 32 additions & 131 deletions pysolr.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,16 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals

import ast
import datetime
import logging
import os
import random
import re
import time
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as _get_version
from xml.etree import ElementTree # noqa: ICN001

import requests

try:
from importlib.metadata import PackageNotFoundError
from importlib.metadata import version as _get_version
except ImportError:
# python < 3.8
from importlib_metadata import PackageNotFoundError
from importlib_metadata import version as _get_version

try:
from kazoo.client import KazooClient, KazooState
except ImportError:
Expand All @@ -31,42 +22,10 @@
except ImportError:
import json

try:
# Python 3.X
from urllib.parse import urlencode
except ImportError:
# Python 2.X
from urllib import urlencode

try:
# Python 3.X
from urllib.parse import quote
except ImportError:
# Python 2.X
from urllib import quote

try:
# Python 3.X
import html.entities as htmlentities
except ImportError:
# Python 2.X
import htmlentitydefs as htmlentities

try:
# Python 3.X
from http.client import HTTPException
except ImportError:
from httplib import HTTPException

try:
# Python 2.X
unicode_char = unichr
except NameError:
# Python 3.X
unicode_char = chr
# Ugh.
long = int # NOQA: A001

import html.entities as htmlentities
from http.client import HTTPException
from urllib.parse import quote, urlencode

__author__ = "Daniel Lindsley, Joseph Kocherhans, Jacob Kaplan-Moss, Thomas Rieder"
__all__ = ["Solr"]
Expand Down Expand Up @@ -110,33 +69,14 @@ def emit(self, record):
LOG.addHandler(stream)


def is_py3():
try:
basestring
return False
except NameError:
return True


IS_PY3 = is_py3()


def force_unicode(value):
"""
Forces a bytestring to become a Unicode string.
"""
if IS_PY3:
# Python 3.X
if isinstance(value, bytes):
value = value.decode("utf-8", errors="replace")
elif not isinstance(value, str):
value = str(value)
else:
# Python 2.X
if isinstance(value, str):
value = value.decode("utf-8", "replace")
elif not isinstance(value, basestring): # NOQA: F821
value = unicode(value) # NOQA: F821
if isinstance(value, bytes):
value = value.decode("utf-8", errors="replace")
elif not isinstance(value, str):
value = str(value)

return value

Expand All @@ -145,12 +85,8 @@ def force_bytes(value):
"""
Forces a Unicode string to become a bytestring.
"""
if IS_PY3:
if isinstance(value, str):
value = value.encode("utf-8", "backslashreplace")
else:
if isinstance(value, unicode): # NOQA: F821
value = value.encode("utf-8")
if isinstance(value, str):
value = value.encode("utf-8", "backslashreplace")

return value

Expand All @@ -171,46 +107,30 @@ def fixup(m):
# character reference
try:
if text[:3] == "&#x":
return unicode_char(int(text[3:-1], 16))
return chr(int(text[3:-1], 16))
else:
return unicode_char(int(text[2:-1]))
return chr(int(text[2:-1]))
except ValueError:
pass
else:
# named entity
try:
text = unicode_char(htmlentities.name2codepoint[text[1:-1]])
text = chr(htmlentities.name2codepoint[text[1:-1]])
except KeyError:
pass
return text # leave as is

return re.sub(r"&#?\w+;", fixup, text)


def safe_urlencode(params, doseq=0):
def safe_urlencode(params, doseq=False):
"""
UTF-8-safe version of safe_urlencode
URL-encode parameters using UTF-8 encoding.

The stdlib safe_urlencode prior to Python 3.x chokes on UTF-8 values
which can't fail down to ascii.
This is a wrapper around `urllib.parse.urlencode` that ensures
consistent UTF-8 handling for all parameter values.
"""
if IS_PY3:
return urlencode(params, doseq)

if hasattr(params, "items"):
params = params.items()

new_params = []

for k, v in params:
k = k.encode("utf-8")

if isinstance(v, (list, tuple)):
new_params.append((k, [force_bytes(i) for i in v]))
else:
new_params.append((k, force_bytes(v)))

return urlencode(new_params, doseq)
return urlencode(params, doseq)


def clean_xml_string(s):
Expand Down Expand Up @@ -622,9 +542,9 @@ def _scrape_response(self, headers, response):
full_html = ""
dom_tree = None

# In Python3, response can be made of bytes
if IS_PY3 and hasattr(response, "decode"):
if hasattr(response, "decode"):
response = response.decode()

if response.startswith("<?xml"):
# Try a strict XML parse
try:
Expand Down Expand Up @@ -707,14 +627,8 @@ def _from_python(self, value):
else:
value = "false"
else:
if IS_PY3:
# Python 3.X
if isinstance(value, bytes):
value = str(value, errors="replace") # NOQA: F821
else:
# Python 2.X
if isinstance(value, str):
value = unicode(value, errors="replace") # NOQA: F821
if isinstance(value, bytes):
value = str(value, errors="replace") # NOQA: F821

value = "{0}".format(value)

Expand All @@ -724,7 +638,7 @@ def _to_python(self, value):
"""
Converts values from Solr to native Python values.
"""
if isinstance(value, (int, float, long, complex)):
if isinstance(value, (int, float, complex)):
return value

if isinstance(value, (list, tuple)):
Expand All @@ -740,18 +654,11 @@ def _to_python(self, value):

is_string = False

if IS_PY3:
if isinstance(value, bytes):
value = force_unicode(value)

if isinstance(value, str):
is_string = True
else:
if isinstance(value, str):
value = force_unicode(value)
if isinstance(value, bytes):
value = force_unicode(value)

if isinstance(value, basestring): # NOQA: F821
is_string = True
if isinstance(value, str):
is_string = True

if is_string:
possible_datetime = DATETIME_REGEX.search(value)
Expand Down Expand Up @@ -791,14 +698,8 @@ def _is_null_value(self, value):
if value is None:
return True

if IS_PY3:
# Python 3.X
if isinstance(value, str) and len(value) == 0:
return True
else:
# Python 2.X
if isinstance(value, basestring) and len(value) == 0: # NOQA: F821
return True
if isinstance(value, str) and len(value) == 0:
return True

# TODO: This should probably be removed when solved in core Solr level?
return False
Expand Down Expand Up @@ -1484,7 +1385,7 @@ def __init__(
auth=None,
verify=True,
*args,
**kwargs
**kwargs,
):
url = zookeeper.getRandomURL(collection)
self.auth = auth
Expand All @@ -1502,7 +1403,7 @@ def __init__(
auth=self.auth,
verify=self.verify,
*args,
**kwargs
**kwargs,
)

def _send_request(self, method, path="", body=None, headers=None, files=None):
Expand Down
3 changes: 0 additions & 3 deletions run-tests.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
#!/usr/bin/env python
# encoding: utf-8

from __future__ import absolute_import, print_function, unicode_literals

import faulthandler
import signal
Expand Down
7 changes: 2 additions & 5 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,8 @@
],
url="https://github.com/django-haystack/pysolr/",
license="BSD",
install_requires=[
"requests>=2.9.1",
"setuptools",
"importlib_metadata; python_version<'3.8'",
],
install_requires=["requests>=2.32.5", "setuptools"],
python_requires=">=3.10",
extras_require={"solrcloud": ["kazoo>=2.5.0"]},
setup_requires=["setuptools_scm"],
)
4 changes: 0 additions & 4 deletions tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# encoding: utf-8

from __future__ import absolute_import, print_function, unicode_literals

from .test_admin import * # NOQA
from .test_client import * # NOQA
from .test_cloud import * # NOQA
4 changes: 0 additions & 4 deletions tests/test_admin.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
# -*- coding: utf-8 -*-

from __future__ import absolute_import, unicode_literals

import unittest

from pysolr import SolrCoreAdmin
Expand Down
Loading
Loading