Skip to content

Commit be8b193

Browse files
search5claude
andcommitted
Release v1.0.2
- mypy --strict passes with zero errors on solr/ package - Add type hints to all internal classes and @committing-decorated methods - Fix endElement variable shadowing (name → tag) for type safety - Remove unnecessary type: ignore comments Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent b1b8910 commit be8b193

5 files changed

Lines changed: 67 additions & 54 deletions

File tree

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ poetry run pytest tests/
9090

9191
## Changelog
9292

93+
### 1.0.2
94+
95+
- `mypy --strict` passes with zero errors on `solr/` package
96+
- Added type hints to all internal classes (`ResponseContentHandler`, `Node`, `Results`, `UTC`)
97+
- Fixed `endElement` variable shadowing for type safety
98+
9399
### 1.0.1
94100

95101
- Added type hints to all public methods in `solr/core.py` and `solr/paginator.py`

docs/changelog.rst

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
Changelog
22
=========
33

4+
1.0.2 (2026-03-27)
5+
-------------------
6+
7+
**Type safety:**
8+
9+
- ``mypy --strict`` now passes with zero errors on the entire ``solr/`` package.
10+
- Added type annotations to all internal classes: ``ResponseContentHandler``,
11+
``Node``, ``Results``, ``UTC``.
12+
- Added type annotations to all ``@committing``-decorated methods (``add``,
13+
``add_many``, ``delete``, ``delete_many``, ``delete_query``).
14+
- Fixed ``endElement`` variable shadowing (``name`` → ``tag``) for type safety.
15+
- Removed unnecessary ``type: ignore`` comments.
16+
17+
418
1.0.1 (2026-03-27)
519
-------------------
620

docs/conf.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@
99
copyright = '2010-2026, solrpy developers'
1010
author = 'solrpy developers'
1111

12-
version = '1.0.1'
13-
release = '1.0.1'
12+
version = '1.0.2'
13+
release = '1.0.2'
1414

1515
# -- General configuration ---------------------------------------------------
1616

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "solrpy"
3-
version = "1.0.1"
3+
version = "1.0.2"
44
description = "Client for the Solr search service"
55
license = "Apache-2.0"
66
readme = "README.md"

solr/core.py

Lines changed: 44 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@
258258
from xml.sax.saxutils import escape, quoteattr
259259
from xml.dom.minidom import parseString
260260

261-
__version__ = "1.0.1"
261+
__version__ = "1.0.2"
262262

263263
__all__ = ['SolrException', 'SolrVersionError', 'Solr', 'SolrConnection',
264264
'Response', 'SearchHandler']
@@ -530,7 +530,7 @@ def _detect_version(self) -> tuple[int, ...]:
530530
# Update interface.
531531

532532
@committing
533-
def delete(self, id=None, ids=None, queries=None):
533+
def delete(self, id: Any = None, ids: list[Any] | None = None, queries: list[str] | None = None) -> str | None:
534534
"""
535535
Delete documents by ids or queries.
536536
@@ -547,7 +547,7 @@ def delete(self, id=None, ids=None, queries=None):
547547
return self._delete(id=id, ids=ids, queries=queries)
548548

549549
@committing
550-
def delete_many(self, ids):
550+
def delete_many(self, ids: list[Any]) -> str | None:
551551
"""
552552
Delete documents using an iterable of ids.
553553
@@ -557,7 +557,7 @@ def delete_many(self, ids):
557557
return self._delete(ids=ids)
558558

559559
@committing
560-
def delete_query(self, query):
560+
def delete_query(self, query: str) -> str | None:
561561
"""
562562
Delete all documents identified by a query.
563563
@@ -567,7 +567,7 @@ def delete_query(self, query):
567567
return self._delete(queries=[query])
568568

569569
@committing
570-
def add(self, doc):
570+
def add(self, doc: dict[str, Any]) -> str:
571571
"""
572572
Add a document to the Solr server. Document fields
573573
should be specified as arguments to this function
@@ -585,7 +585,7 @@ def add(self, doc):
585585
return ''.join(lst)
586586

587587
@committing
588-
def add_many(self, docs):
588+
def add_many(self, docs: Iterable[dict[str, Any]]) -> str:
589589
"""
590590
Add several documents to the Solr server.
591591
@@ -746,7 +746,7 @@ class SolrConnection(Solr):
746746

747747
# Backward compatible update interfaces.
748748

749-
def add(self, _commit: bool = False, **fields: Any) -> Any: # type: ignore[override]
749+
def add(self, _commit: bool = False, **fields: Any) -> Any:
750750
"""
751751
Add or update a single document with field values given by
752752
keyword arguments.
@@ -764,7 +764,7 @@ def add(self, _commit: bool = False, **fields: Any) -> Any: # type: ignore[over
764764
"""
765765
return Solr.add_many(self, [fields], commit=_commit)
766766

767-
def add_many(self, docs: Iterable[dict[str, Any]], _commit: bool = False) -> Any: # type: ignore[override]
767+
def add_many(self, docs: Iterable[dict[str, Any]], _commit: bool = False) -> Any:
768768
"""
769769
Add or update multiple documents. with field values for each given
770770
by dictionaries in the sequence `docs`.
@@ -1084,11 +1084,11 @@ class ResponseContentHandler(ContentHandler):
10841084
ContentHandler for the XML results of a /select call.
10851085
(Versions 2.2 (and possibly 2.1))
10861086
"""
1087-
def __init__(self):
1088-
self.stack = [Node(None, {})]
1089-
self.in_tree = False
1087+
def __init__(self) -> None:
1088+
self.stack: list[Node] = [Node(None, {})]
1089+
self.in_tree: bool = False
10901090

1091-
def startElement(self, name, attrs):
1091+
def startElement(self, name: str, attrs: Any) -> None:
10921092
if not self.in_tree:
10931093
if name != 'response':
10941094
raise SolrException(
@@ -1104,98 +1104,91 @@ def startElement(self, name, attrs):
11041104
# Keep track of children
11051105
self.stack[-2].children.append(element)
11061106

1107-
def characters (self, ch):
1107+
def characters(self, ch: str) -> None:
11081108
self.stack[-1].chars.append(ch)
11091109

1110-
def endElement(self, name):
1110+
def endElement(self, name: str) -> None:
11111111
node = self.stack.pop()
11121112

1113-
name = node.name
1113+
tag = node.name or name
11141114
value = "".join(node.chars)
11151115

1116-
if name == 'int':
1116+
if tag == 'int':
11171117
node.final = int(value.strip())
11181118

1119-
elif name == 'str':
1119+
elif tag == 'str':
11201120
node.final = value
11211121

1122-
elif name == 'null':
1122+
elif tag == 'null':
11231123
node.final = None
11241124

1125-
elif name == 'long':
1125+
elif tag == 'long':
11261126
node.final = int(value.strip())
11271127

1128-
elif name == 'bool':
1128+
elif tag == 'bool':
11291129
node.final = value.strip().lower().startswith('t')
11301130

1131-
elif name == 'date':
1132-
node.final = utc_from_string(value.strip())
1131+
elif tag == 'date':
1132+
node.final = utc_from_string(value.strip())
11331133

1134-
elif name in ('float','double', 'status','QTime'):
1134+
elif tag in ('float', 'double', 'status', 'QTime'):
11351135
node.final = float(value.strip())
11361136

1137-
elif name == 'response':
1137+
elif tag == 'response':
11381138
node.final = response = Response(self)
11391139
for child in node.children:
1140-
name = child.attrs.get('name', child.name)
1141-
if name == 'responseHeader':
1142-
name = 'header'
1140+
child_name = child.attrs.get('name', child.name)
1141+
if child_name == 'responseHeader':
1142+
child_name = 'header'
11431143
elif child.name == 'result':
1144-
name = 'results'
1144+
child_name = 'results'
11451145
for attr_name in child.attrs.getNames():
1146-
# We already know it is a response
11471146
if attr_name != "name":
11481147
setattr(response, attr_name, child.attrs.get(attr_name))
11491148

1150-
setattr(response, name, child.final)
1149+
setattr(response, child_name, child.final)
11511150

1152-
elif name in ('lst','doc'):
1153-
# Represent these with a dict
1151+
elif tag in ('lst', 'doc'):
11541152
node.final = dict(
11551153
[(cnode.attrs['name'], cnode.final)
11561154
for cnode in node.children])
11571155

1158-
elif name in ('arr',):
1156+
elif tag in ('arr',):
11591157
node.final = [cnode.final for cnode in node.children]
11601158

1161-
elif name == 'result':
1159+
elif tag == 'result':
11621160
node.final = Results([cnode.final for cnode in node.children])
11631161

1164-
1165-
elif name in ('responseHeader',):
1162+
elif tag in ('responseHeader',):
11661163
node.final = dict([(cnode.name, cnode.final)
11671164
for cnode in node.children])
11681165
else:
1169-
raise SolrException("Unknown tag: %s" % name)
1166+
raise SolrException("Unknown tag: %s" % tag)
11701167

11711168
for attr, val in node.attrs.items():
11721169
if attr != 'name':
11731170
setattr(node.final, attr, val)
11741171

11751172

1176-
class Results(list):
1173+
class Results(list[Any]):
11771174
"""
11781175
Convenience class containing <result> items
11791176
"""
11801177
pass
11811178

11821179

1183-
class Node(object):
1180+
class Node:
11841181
"""
11851182
A temporary object used in XML processing. Not seen by end user.
11861183
"""
1187-
def __init__(self, name, attrs):
1188-
"""
1189-
Final will eventually be the "final" representation of
1190-
this node, whether an int, list, dict, etc.
1191-
"""
1192-
self.chars = []
1184+
def __init__(self, name: str | None, attrs: Any) -> None:
1185+
self.chars: list[str] = []
11931186
self.name = name
11941187
self.attrs = attrs
1195-
self.final = None
1196-
self.children = []
1188+
self.final: Any = None
1189+
self.children: list[Node] = []
11971190

1198-
def __repr__(self):
1191+
def __repr__(self) -> str:
11991192
return '<%s val="%s" %s>' % (
12001193
self.name,
12011194
"".join(self.chars).strip(),
@@ -1233,13 +1226,13 @@ class UTC(datetime.tzinfo):
12331226
"""
12341227
UTC timezone.
12351228
"""
1236-
def utcoffset(self, dt):
1229+
def utcoffset(self, dt: datetime.datetime | None) -> datetime.timedelta:
12371230
return datetime.timedelta(0)
12381231

1239-
def tzname(self, dt):
1232+
def tzname(self, dt: datetime.datetime | None) -> str:
12401233
return "UTC"
12411234

1242-
def dst(self, dt):
1235+
def dst(self, dt: datetime.datetime | None) -> datetime.timedelta:
12431236
return datetime.timedelta(0)
12441237

12451238

0 commit comments

Comments
 (0)