Skip to content
This repository was archived by the owner on Feb 18, 2026. It is now read-only.

Commit 1c35f87

Browse files
committed
Add python client generator fixes
1 parent a37a50c commit 1c35f87

7 files changed

Lines changed: 2347 additions & 12 deletions

File tree

clients/python-compat/README.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# Python Client Compatibility Layer
2+
3+
This directory contains the backward compatibility layer for the OpenAPI v7 generated Python client.
4+
5+
## Purpose
6+
7+
The v7 OpenAPI generator produces clients with breaking changes from v5:
8+
- `@validate_call` rejects unknown kwargs like `async_req`
9+
- Union types (oneOf/anyOf) require `.actual_instance` access
10+
- ModelSimple wrappers removed (no more `.value` on Height, TxInputs, etc.)
11+
- Pydantic v2 models don't support dict-style access
12+
13+
This compatibility layer patches the generated client to maintain backward compatibility with existing user code.
14+
15+
## Files
16+
17+
- `patch_compat.py` - Post-processing script that patches the generated client
18+
- `test_compat.py` - Comprehensive tests for backward compatibility
19+
- `README.md` - This file
20+
21+
## Usage
22+
23+
The patch script is called automatically by the Makefile after code generation:
24+
25+
```bash
26+
cd clients/python
27+
make generate-openapi-client
28+
```
29+
30+
To run just the compatibility tests:
31+
32+
```bash
33+
python clients/python-compat/test_compat.py
34+
# Or specify a client directory:
35+
python clients/python-compat/test_compat.py clients/python
36+
```
37+
38+
## What Gets Patched
39+
40+
### 1. Compat Types (`compat.py`)
41+
42+
- **CompatInt**: Integer subclass with `.value` property and arithmetic that preserves type
43+
- **CompatList**: List subclass with `.value` property
44+
- **DictModel**: Dict wrapper with attribute access for oneOf/anyOf models
45+
- **Height**: Alias for CompatInt
46+
47+
### 2. Model Files
48+
49+
- Height fields (`height`, `before_block`, `after_block`) wrapped in CompatInt
50+
- List fields (`inputs`, `outputs`, `actors`, `address`) wrapped in CompatList
51+
- OneOf models get transparent `__getattr__` delegation to `actual_instance`
52+
53+
### 3. API Files
54+
55+
- `@validate_call` replaced with `@validate_call_compat` that:
56+
- Accepts `async_req`, `_preload_content`, `_return_http_data_only` kwargs
57+
- Converts datetime to ISO 8601 strings for date parameters
58+
- Submits to thread pool when `async_req=True`
59+
60+
### 4. ApiClient
61+
62+
- `pool_threads` parameter creates ThreadPoolExecutor for async support
63+
- List responses wrapped in CompatList
64+
- Headers properly converted to dict
65+
66+
## Features
67+
68+
### Arithmetic Preservation (Fix 3)
69+
```python
70+
h = CompatInt(100)
71+
result = h + 1 # Returns CompatInt(101), not plain int
72+
result.value # Still works: 101
73+
```
74+
75+
### Dict Protocol (Fix 2)
76+
```python
77+
d = DictModel({'a': 1, 'b': 2})
78+
'a' in d # True
79+
len(d) # 2
80+
list(d.keys()) # ['a', 'b']
81+
```
82+
83+
### Serialization (Fix 4)
84+
```python
85+
import pickle, copy
86+
h = CompatInt(100)
87+
pickle.loads(pickle.dumps(h)) # CompatInt(100)
88+
copy.deepcopy(h) # CompatInt(100)
89+
```
90+
91+
### Caching (Fix 5)
92+
```python
93+
d = DictModel({'nested': {'x': 1}})
94+
d.nested is d.nested # True (cached)
95+
```
96+
97+
### Thread Pool (Fix 1)
98+
```python
99+
# Default pool_threads=1 now creates a thread pool
100+
with ApiClient(config, pool_threads=1) as client:
101+
api = AddressesApi(client)
102+
result = api.get_address("btc", "addr", async_req=True)
103+
data = result.get() # Blocks until complete
104+
```
105+
106+
## Known Limitations
107+
108+
- Nested lists in models are not wrapped in CompatList (only top-level)
109+
- Thread pool warning when `async_req=True` but `pool_threads=0`

0 commit comments

Comments
 (0)