Skip to content

Commit d36bee8

Browse files
Nicole00盐粒 Yanli
andauthored
cherrypick master fix (#410)
* run ruff and fix lint (#385) * [Feature] Support borrow session for contextual execution (#386) * support borrow session on client * add doc * run lint * fix typo (#387) * add example for NebulaPool (#390) * fix time overflow for hour 25 (#391) * fix None list value (#392) * fix duration type bug (#395) * update doc for special types (#396) * upadte doc for special types * update start desc * update doc (#397) --------- Co-authored-by: 盐粒 Yanli <yanli.yu@vesoft.com>
1 parent e4f35ab commit d36bee8

21 files changed

Lines changed: 315 additions & 181 deletions

.github/workflows/update_version.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
from typing import Optional
88

99

10-
def update_version(version_type: str = "dev", custom_suffix: Optional[str] = None) -> str:
10+
def update_version(
11+
version_type: str = "dev", custom_suffix: Optional[str] = None
12+
) -> str:
1113
"""
1214
Update the `version` field in `pyproject.toml` for supported manual build types.
1315
@@ -25,17 +27,21 @@ def update_version(version_type: str = "dev", custom_suffix: Optional[str] = Non
2527
content: str = pyproject_path.read_text()
2628

2729
# Extract current version
28-
version_match: Optional[re.Match[str]] = re.search(r'^version\s*=\s*"([^"]+)"', content, re.MULTILINE)
30+
version_match: Optional[re.Match[str]] = re.search(
31+
r'^version\s*=\s*"([^"]+)"', content, re.MULTILINE
32+
)
2933
if not version_match:
3034
raise ValueError("Could not find version in pyproject.toml")
3135

3236
current_version: str = version_match.group(1)
33-
37+
3438
# Parse the base version (remove any existing suffixes)
35-
base_version_match: Optional[re.Match[str]] = re.match(r'^(\d+\.\d+\.\d+)', current_version)
39+
base_version_match: Optional[re.Match[str]] = re.match(
40+
r"^(\d+\.\d+\.\d+)", current_version
41+
)
3642
if not base_version_match:
3743
raise ValueError(f"Invalid version format: {current_version}")
38-
44+
3945
base_version: str = base_version_match.group(1)
4046

4147
# Only dev/custom builds mutate the version; all others keep current version

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,6 @@ cython_debug/
161161
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
162162
# and can be added to the global gitignore or merged into this file. For a more nuclear
163163
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
164-
#.idea/
165-
.idea
164+
.idea/
166165
.DS_Store
167166
docs/.DS_Store

docs/1_started.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
# NebulaGraph Python Client Getting Started
22

33
## Installation
4+
from pypi
45

56
```bash
6-
pip install ng-python # not yet published
7+
pip install nebula5_python==5.2.0
78
```
89

910
from source
1011

1112
```bash
12-
cd python
13+
git clone -b dev https://github.com/vesoft-inc/nebula-python.git
14+
cd nebula-python
1315
pip install -e .
1416
```
1517

@@ -125,6 +127,23 @@ with NebulaClient(
125127

126128
If you prefer manual lifecycle control, you can explicitly open and close clients.
127129

130+
- Sync version:
131+
132+
```python
133+
from nebulagraph_python import NebulaClient
134+
135+
client = NebulaClient(
136+
hosts=["127.0.0.1:9669"],
137+
username="root",
138+
password="NebulaGraph01",
139+
)
140+
try:
141+
result = client.execute("RETURN 1 AS a, 2 AS b")
142+
result.print()
143+
finally:
144+
client.close()
145+
```
146+
128147
- Async version:
129148

130149
```python
@@ -152,4 +171,4 @@ Run `ngcli --help` to get the help message. An example to connect to NebulaGraph
152171

153172
```bash
154173
ngcli -h 127.0.0.1:9669 -u root -p NebulaGraph01
155-
```
174+
```

docs/2_concurrency.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,26 @@ async def concurrent_example():
6262
asyncio.run(concurrent_example())
6363
```
6464

65+
## Contextual Execution
66+
67+
By default, statements run on a random session from the pool. When you need to run several queries on the same session, call `borrow` to obtain and reuse a specific session.
68+
69+
```python
70+
async def contextual_example():
71+
async with await NebulaAsyncClient.connect(
72+
hosts=["127.0.0.1:9669"],
73+
username="root",
74+
password="NebulaGraph01",
75+
session_pool_config=SessionPoolConfig(),
76+
) as client:
77+
print("Connected to the server...")
78+
async with client.borrow() as session:
79+
await session.execute("SESSION SET GRAPH movie")
80+
res = await session.execute("MATCH (v:Movie) RETURN count(v)")
81+
res.print()
82+
```
83+
84+
6585
## Understanding Timeout Values
6686

6787
The client uses three different timeouts that apply at different stages:

docs/5_vector_and_special_types.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,15 +53,15 @@ cli.close()
5353
### NDuration
5454

5555
`NDuration` represents a duration with support for both month-based and time-based forms.
56-
- If `months != 0`, the instance is month-based (`is_month_based = True`), and `years`/`months` are derived from the `months` argument.
57-
- If `months == 0`, the instance is time-based (days default to 0 in current implementation) and uses the `seconds` and `microseconds` arguments to derive `hour`, `minute`, `second`, `microsec`.
56+
- If `is_month_based = True`, the instance uses `year` and `month` fields for duration representation.
57+
- If `is_month_based = False`, the instance uses `day`, `hour`, `minute`, `second`, and `microsecond` fields for duration representation.
5858

5959
The `__str__` produces an ISO-8601–like string:
6060
- Month-based examples: `P1Y2M`, `P0M`
6161
- Time-based examples: `PT0S`, `PT1H2M3S`, `PT3.5S`, `PT-0.000123S`
6262

6363
API:
64-
- Constructor: `NDuration(seconds: int, microseconds: int, months: int)`
64+
- Constructor: `NDuration(is_month_based: bool, year: int, month: int, day: int, hour: int, minute: int, seconds: int, microseconds: int)`
6565
- Properties/Methods:
6666
- `is_month_based: bool`
6767
- `get_year() -> int`, `get_month() -> int`, `get_day() -> int`

docs/7_orm_example.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ class Edge1(
117117

118118
if input("Execute the DDL? (y/N)") == "y":
119119
client.execute_py(graph_type.to_gql())
120-
client.execute_py("CREATE GRAPH IF NOT EXISTS define_type_test define_type_test_type")
120+
client.execute_py(
121+
"CREATE GRAPH IF NOT EXISTS define_type_test define_type_test_type"
122+
)
121123

122124

123125
q = upsert_gql(

example.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ def sync_session_pool_example():
187187
if __name__ == "__main__":
188188
import asyncio
189189
import logging
190+
190191
logging.basicConfig(level=logging.DEBUG)
191192
logging.getLogger("nebulagraph_python").setLevel(logging.DEBUG)
192193

example/NebulaPoolExample.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env python3
2+
# -*- coding: utf-8 -*-
3+
4+
from typing import Optional, Dict
5+
from nebulagraph_python.client.pool import NebulaPool
6+
from nebulagraph_python.data import HostAddress
7+
from dataclasses import dataclass, field
8+
9+
@dataclass
10+
class SessionConfig:
11+
schema: Optional[str] = None
12+
graph: Optional[str] = None
13+
timezone: Optional[str] = None
14+
values: Dict[str, str] = field(default_factory=dict)
15+
configs: Dict[str, str] = field(default_factory=dict)
16+
17+
graph_name = "test_graph"
18+
19+
def main():
20+
# config the connect information
21+
hosts = ["127.0.0.1:9669"]
22+
username = "root"
23+
password = "NebulaGraph01"
24+
25+
# create NebulaPool
26+
pool = NebulaPool(
27+
hosts=hosts,
28+
username=username,
29+
password=password,
30+
session_config=SessionConfig(graph=graph_name)
31+
)
32+
33+
try:
34+
print("use execute_py to execute `SHOW GRAPHS` ...")
35+
result = pool.execute_py("SHOW GRAPHS")
36+
37+
# 打印结果
38+
print("\n query result:")
39+
print("-" * 50)
40+
result.print(style="table")
41+
42+
print("\n\nuse execute to execute `SHOW GRAPHS`:")
43+
print("-" * 50)
44+
result2 = pool.execute("SHOW GRAPHS")
45+
result2.print(style="table")
46+
47+
# get the query result
48+
print("-" * 50)
49+
if result.size > 0:
50+
for row in result:
51+
print(f"Row: {row}")
52+
else:
53+
print("Empty")
54+
55+
except Exception as e:
56+
print(f"\nerror: {e}")
57+
import traceback
58+
traceback.print_exc()
59+
finally:
60+
print("\nclose the pool...")
61+
pool.close()
62+
print("closed")
63+
64+
65+
if __name__ == "__main__":
66+
main()

run_example.sh

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#!/bin/bash
2+
# run example program, using local source code and dependencies
3+
4+
export PYTHONPATH="${PYTHONPATH}:$(pwd)/src:$(pwd)/deps"
5+
6+
python3 example/NebulaPoolExample.py

scripts/add_apache_headers.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,4 +203,3 @@ def main() -> None:
203203

204204
if __name__ == "__main__":
205205
main()
206-

0 commit comments

Comments
 (0)