Skip to content

Commit 51024d0

Browse files
search5claude
andcommitted
Release v2.0.4: Unified sync/async API + conn.conn cleanup + ZooKeeper docs
- Unified sync/async: SchemaAPI, KNN, MoreLikeThis, Suggest, Extract accept both Solr and AsyncSolr. DualTransport + _chain() helper. - AsyncSchemaAPI etc. kept as backward-compatible aliases. - Renamed Solr.conn/AsyncSolr.conn to _client (encapsulation). - Expanded SolrCloud/SolrZooKeeper docs: full method descriptions, parameters, return types, examples, failover behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8b8f736 commit 51024d0

20 files changed

Lines changed: 942 additions & 363 deletions

README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,14 @@ poetry run pytest tests/
102102

103103
## Changelog
104104

105+
### 2.0.4
106+
107+
- **Unified sync/async API**: `SchemaAPI(conn)` works with both `Solr` and `AsyncSolr`
108+
- Single class, dual mode — no need for separate `AsyncSchemaAPI` etc.
109+
- `DualTransport` auto-detects sync vs async connection
110+
- `_chain()` helper for composing sync values and async coroutines
111+
- `AsyncSchemaAPI`, `AsyncKNN`, `AsyncMoreLikeThis`, `AsyncSuggest`, `AsyncExtract` kept as backward-compatible aliases
112+
105113
### 2.0.3
106114

107115
- **Async companion classes**: `AsyncSchemaAPI`, `AsyncKNN`, `AsyncMoreLikeThis`, `AsyncSuggest`, `AsyncExtract`

docs/changelog.rst

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

4+
2.0.4 (2026-03-27)
5+
-------------------
6+
7+
**New features:**
8+
9+
- **Unified sync/async API**: all companion classes (``SchemaAPI``, ``KNN``,
10+
``MoreLikeThis``, ``Suggest``, ``Extract``) now accept both ``Solr`` (sync)
11+
and ``AsyncSolr`` (async) connections.
12+
- With a sync connection, methods return values directly. With an async
13+
connection, methods return coroutines (to be ``await``-ed).
14+
- **``DualTransport``** in ``solr/transport.py``: auto-detects sync vs async
15+
and delegates to ``SolrTransport`` or ``AsyncTransport`` accordingly.
16+
- **``_chain()``** helper composes a transform onto either a sync value or
17+
an async coroutine, eliminating code duplication in companion classes.
18+
- ``AsyncSchemaAPI``, ``AsyncKNN``, ``AsyncMoreLikeThis``, ``AsyncSuggest``,
19+
and ``AsyncExtract`` are kept as backward-compatible aliases.
20+
21+
**Example:**
22+
23+
.. code-block:: python
24+
25+
from solr import Solr, AsyncSolr, SchemaAPI
26+
27+
# Sync — returns list directly
28+
conn = Solr('http://localhost:8983/solr/mycore')
29+
schema = SchemaAPI(conn)
30+
fields = schema.fields()
31+
32+
# Async — returns coroutine
33+
async with AsyncSolr('http://localhost:8983/solr/mycore') as conn:
34+
schema = SchemaAPI(conn)
35+
fields = await schema.fields()
36+
37+
438
2.0.3 (2026-03-27)
539
-------------------
640

docs/quickstart.rst

Lines changed: 95 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -521,15 +521,23 @@ Priority: ``auth`` callable > ``auth_token`` > ``http_user/http_pass``.
521521
SolrCloud
522522
---------
523523

524-
**With ZooKeeper** (real-time node discovery, requires ``kazoo``)::
524+
Install ZooKeeper support::
525+
526+
pip install solrpy[cloud]
527+
528+
**With ZooKeeper** (real-time node discovery via ``kazoo``)::
525529

526530
from solr import SolrZooKeeper, SolrCloud
527531

528-
zk = SolrZooKeeper('zk1:2181,zk2:2181')
529-
cloud = SolrCloud(zk, collection='mycore')
532+
zk = SolrZooKeeper('zk1:2181,zk2:2181,zk3:2181')
533+
cloud = SolrCloud(zk, collection='products')
530534

531-
response = cloud.select('*:*')
532-
cloud.add({'id': '1', 'title': 'test'}, commit=True)
535+
# Reads go to any active replica (automatic failover)
536+
response = cloud.select('category:books', rows=20)
537+
538+
# Writes are routed to shard leaders
539+
cloud.add({'id': '1', 'title': 'Solr in Action'}, commit=True)
540+
cloud.delete(id='1', commit=True)
533541

534542
cloud.close()
535543
zk.close()
@@ -540,14 +548,58 @@ SolrCloud
540548

541549
cloud = SolrCloud.from_urls(
542550
['http://solr1:8983/solr', 'http://solr2:8983/solr'],
543-
collection='mycore')
551+
collection='products')
544552

545553
response = cloud.select('*:*')
546554
cloud.close()
547555

548-
Install ZooKeeper support::
556+
Pass connection options (timeout, auth, SSL) via ``**solr_kwargs``::
549557

550-
pip install solrpy[cloud]
558+
cloud = SolrCloud(zk, collection='secure',
559+
timeout=10,
560+
auth_token='my-jwt-token')
561+
562+
Failover retries default to 3 with exponential backoff::
563+
564+
# Customize retry behavior
565+
cloud = SolrCloud(zk, collection='products',
566+
retry_count=5, retry_delay=1.0)
567+
568+
569+
Using SolrZooKeeper directly
570+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
571+
572+
You can also use ``SolrZooKeeper`` independently for cluster inspection::
573+
574+
from solr import SolrZooKeeper
575+
576+
zk = SolrZooKeeper('zk1:2181,zk2:2181')
577+
578+
# List active nodes
579+
print(zk.live_nodes())
580+
# ['solr1:8983_solr', 'solr2:8983_solr', 'solr3:8983_solr']
581+
582+
# Get all replica URLs for a collection
583+
replicas = zk.replica_urls('products')
584+
# ['http://solr1:8983/solr', 'http://solr2:8983/solr']
585+
586+
# Get shard leader URLs (one per shard)
587+
leaders = zk.leader_urls('products')
588+
# ['http://solr1:8983/solr']
589+
590+
# Check collection aliases
591+
aliases = zk.aliases()
592+
# {'prod': 'products_v2', 'staging': 'products_v1'}
593+
594+
# Aliases are resolved automatically in replica_urls/leader_urls
595+
zk.replica_urls('prod') # same as zk.replica_urls('products_v2')
596+
597+
# Inspect collection state (shards, replicas, router)
598+
state = zk.collection_state('products')
599+
for shard, data in state['shards'].items():
600+
print(shard, len(data['replicas']), 'replicas')
601+
602+
zk.close()
551603

552604

553605
Pydantic response models
@@ -576,6 +628,41 @@ Convert search results to typed Pydantic models (``pip install solrpy[pydantic]`
576628
products = resp.as_models(Product)
577629

578630

631+
Async usage
632+
-----------
633+
634+
Use ``AsyncSolr`` for async/await support (e.g. in FastAPI, aiohttp)::
635+
636+
from solr import AsyncSolr
637+
638+
async with AsyncSolr('http://localhost:8983/solr/mycore') as conn:
639+
response = await conn.select('*:*')
640+
for doc in response.results:
641+
print(doc['id'])
642+
643+
Unified sync/async companions
644+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
645+
646+
Since 2.0.4, all companion classes work with both ``Solr`` and ``AsyncSolr``.
647+
No need for separate ``AsyncSchemaAPI``, ``AsyncKNN``, etc.::
648+
649+
from solr import Solr, AsyncSolr, SchemaAPI, KNN
650+
651+
# Sync
652+
conn = Solr('http://localhost:8983/solr/mycore')
653+
schema = SchemaAPI(conn)
654+
fields = schema.fields()
655+
656+
# Async — same class, returns coroutines
657+
async with AsyncSolr('http://localhost:8983/solr/mycore') as conn:
658+
schema = SchemaAPI(conn)
659+
fields = await schema.fields()
660+
661+
The ``AsyncSchemaAPI``, ``AsyncKNN``, ``AsyncMoreLikeThis``,
662+
``AsyncSuggest``, and ``AsyncExtract`` names are kept as backward-compatible
663+
aliases.
664+
665+
579666
Closing the connection
580667
----------------------
581668

0 commit comments

Comments
 (0)