reydb 1.1.52__py3-none-any.whl → 1.1.53__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reydb/rbase.py +90 -2
- reydb/rconfig.py +3 -3
- reydb/rconn.py +185 -15
- reydb/rdb.py +110 -24
- reydb/rexec.py +999 -293
- reydb/rfile.py +1 -1
- reydb/rorm.py +233 -36
- {reydb-1.1.52.dist-info → reydb-1.1.53.dist-info}/METADATA +1 -1
- reydb-1.1.53.dist-info/RECORD +17 -0
- reydb-1.1.52.dist-info/RECORD +0 -17
- {reydb-1.1.52.dist-info → reydb-1.1.53.dist-info}/WHEEL +0 -0
- {reydb-1.1.52.dist-info → reydb-1.1.53.dist-info}/licenses/LICENSE +0 -0
reydb/rbase.py
CHANGED
@@ -9,19 +9,28 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
-
from typing import Any, TypedDict, Literal
|
12
|
+
from typing import Any, TypedDict, Literal
|
13
|
+
from enum import EnumType
|
14
|
+
from sqlalchemy import text as sqlalchemy_text
|
13
15
|
from sqlalchemy.engine.base import Engine, Connection
|
14
16
|
from sqlalchemy.engine.url import URL
|
15
17
|
from sqlalchemy.sql.elements import TextClause
|
16
18
|
from reykit.rbase import Base, throw
|
17
19
|
from reykit.rre import search
|
18
20
|
|
21
|
+
from reykit.rdata import to_json
|
22
|
+
from reykit.rre import findall
|
23
|
+
|
19
24
|
|
20
25
|
__all__ = (
|
21
26
|
'DatabaseBase',
|
27
|
+
'handle_sql',
|
28
|
+
'handle_data',
|
22
29
|
'extract_url',
|
23
30
|
'extract_engine',
|
24
|
-
'extract_path'
|
31
|
+
'extract_path',
|
32
|
+
'get_syntax',
|
33
|
+
'is_multi_sql'
|
25
34
|
)
|
26
35
|
|
27
36
|
|
@@ -47,6 +56,85 @@ class DatabaseBase(Base):
|
|
47
56
|
"""
|
48
57
|
|
49
58
|
|
59
|
+
def handle_sql(sql: str | TextClause) -> TextClause:
|
60
|
+
"""
|
61
|
+
Handle SQL.
|
62
|
+
|
63
|
+
Parameters
|
64
|
+
----------
|
65
|
+
sql : SQL in method `sqlalchemy.text` format, or TextClause object.
|
66
|
+
|
67
|
+
Returns
|
68
|
+
-------
|
69
|
+
TextClause instance.
|
70
|
+
"""
|
71
|
+
|
72
|
+
# Handle parameter.
|
73
|
+
if type(sql) == TextClause:
|
74
|
+
sql = sql.text
|
75
|
+
|
76
|
+
# Handle.
|
77
|
+
sql = sql.strip()
|
78
|
+
if sql[-1] != ';':
|
79
|
+
sql += ';'
|
80
|
+
sql = sqlalchemy_text(sql)
|
81
|
+
|
82
|
+
return sql
|
83
|
+
|
84
|
+
|
85
|
+
def handle_data(data: list[dict], sql: str | TextClause) -> list[dict]:
|
86
|
+
"""
|
87
|
+
Handle data based on the content of SQL.
|
88
|
+
|
89
|
+
Parameters
|
90
|
+
----------
|
91
|
+
data : Data set for filling.
|
92
|
+
sql : SQL in method `sqlalchemy.text` format, or TextClause object.
|
93
|
+
|
94
|
+
Returns
|
95
|
+
-------
|
96
|
+
Filled data.
|
97
|
+
"""
|
98
|
+
|
99
|
+
# Handle parameter.
|
100
|
+
if type(sql) == TextClause:
|
101
|
+
sql = sql.text
|
102
|
+
|
103
|
+
# Extract keys.
|
104
|
+
pattern = '(?<!\\\\):(\\w+)'
|
105
|
+
sql_keys = findall(pattern, sql)
|
106
|
+
|
107
|
+
# Extract keys of syntax "in".
|
108
|
+
pattern = '[iI][nN]\\s+(?<!\\\\):(\\w+)'
|
109
|
+
sql_keys_in = findall(pattern, sql)
|
110
|
+
|
111
|
+
# Loop.
|
112
|
+
for row in data:
|
113
|
+
if row == {}:
|
114
|
+
continue
|
115
|
+
for key in sql_keys:
|
116
|
+
value = row.get(key)
|
117
|
+
|
118
|
+
# Empty string.
|
119
|
+
if value == '':
|
120
|
+
value = None
|
121
|
+
|
122
|
+
# Convert.
|
123
|
+
elif (
|
124
|
+
type(value) in (list, dict)
|
125
|
+
and key not in sql_keys_in
|
126
|
+
):
|
127
|
+
value = to_json(value)
|
128
|
+
|
129
|
+
# Enum.
|
130
|
+
elif isinstance(type(value), EnumType):
|
131
|
+
value = value.value
|
132
|
+
|
133
|
+
row[key] = value
|
134
|
+
|
135
|
+
return data
|
136
|
+
|
137
|
+
|
50
138
|
def extract_url(url: str | URL) -> URLParameters:
|
51
139
|
"""
|
52
140
|
Extract parameters from URL of string.
|
reydb/rconfig.py
CHANGED
@@ -17,7 +17,7 @@ from datetime import (
|
|
17
17
|
time as Time,
|
18
18
|
timedelta as Timedelta
|
19
19
|
)
|
20
|
-
from reykit.rbase import
|
20
|
+
from reykit.rbase import Null, throw
|
21
21
|
|
22
22
|
from .rdb import Database
|
23
23
|
|
@@ -445,10 +445,10 @@ class DatabaseConfig(object):
|
|
445
445
|
"""
|
446
446
|
|
447
447
|
# Get.
|
448
|
-
value = self.get(key,
|
448
|
+
value = self.get(key, Null)
|
449
449
|
|
450
450
|
# Check.
|
451
|
-
if value ==
|
451
|
+
if value == Null:
|
452
452
|
throw(KeyError, key)
|
453
453
|
|
454
454
|
return value
|
reydb/rconn.py
CHANGED
@@ -10,7 +10,8 @@
|
|
10
10
|
|
11
11
|
|
12
12
|
from typing import Self
|
13
|
-
from sqlalchemy import Transaction
|
13
|
+
from sqlalchemy import Connection, Transaction
|
14
|
+
from sqlalchemy.ext.asyncio import AsyncConnection, AsyncTransaction
|
14
15
|
|
15
16
|
from .rbase import DatabaseBase
|
16
17
|
from .rdb import Database
|
@@ -18,6 +19,7 @@ from .rdb import Database
|
|
18
19
|
|
19
20
|
__all__ = (
|
20
21
|
'DatabaseConnection',
|
22
|
+
'DatabaseConnectionAsync'
|
21
23
|
)
|
22
24
|
|
23
25
|
|
@@ -47,11 +49,44 @@ class DatabaseConnection(DatabaseBase):
|
|
47
49
|
# Build.
|
48
50
|
self.db = db
|
49
51
|
self.autocommit = autocommit
|
50
|
-
self.
|
51
|
-
self.
|
52
|
+
self.execute = DatabaseExecute(self)
|
53
|
+
self.conn: Connection | None = None
|
52
54
|
self.begin: Transaction | None = None
|
53
55
|
|
54
56
|
|
57
|
+
def get_conn(self) -> Connection:
|
58
|
+
"""
|
59
|
+
Get `Connection` instance.
|
60
|
+
|
61
|
+
Returns
|
62
|
+
-------
|
63
|
+
Instance.
|
64
|
+
"""
|
65
|
+
|
66
|
+
# Create.
|
67
|
+
if self.conn is None:
|
68
|
+
self.conn = self.db.engine.connect()
|
69
|
+
|
70
|
+
return self.conn
|
71
|
+
|
72
|
+
|
73
|
+
def get_begin(self) -> Transaction:
|
74
|
+
"""
|
75
|
+
Get `Transaction` instance.
|
76
|
+
|
77
|
+
Returns
|
78
|
+
-------
|
79
|
+
Instance.
|
80
|
+
"""
|
81
|
+
|
82
|
+
# Create.
|
83
|
+
if self.begin is None:
|
84
|
+
conn = self.get_conn()
|
85
|
+
self.begin = conn.begin()
|
86
|
+
|
87
|
+
return self.begin
|
88
|
+
|
89
|
+
|
55
90
|
def commit(self) -> None:
|
56
91
|
"""
|
57
92
|
Commit cumulative executions.
|
@@ -80,7 +115,12 @@ class DatabaseConnection(DatabaseBase):
|
|
80
115
|
"""
|
81
116
|
|
82
117
|
# Close.
|
83
|
-
self.
|
118
|
+
if self.begin is not None:
|
119
|
+
self.begin.close()
|
120
|
+
self.begin = None
|
121
|
+
if self.conn is not None:
|
122
|
+
self.conn.close()
|
123
|
+
self.conn = None
|
84
124
|
|
85
125
|
|
86
126
|
def __enter__(self) -> Self:
|
@@ -117,30 +157,160 @@ class DatabaseConnection(DatabaseBase):
|
|
117
157
|
self.close()
|
118
158
|
|
119
159
|
|
120
|
-
|
160
|
+
def insert_id(self) -> int:
|
161
|
+
"""
|
162
|
+
Return last self increasing ID.
|
163
|
+
|
164
|
+
Returns
|
165
|
+
-------
|
166
|
+
ID.
|
167
|
+
"""
|
168
|
+
|
169
|
+
# Get.
|
170
|
+
sql = 'SELECT LAST_INSERT_ID()'
|
171
|
+
result = self.execute(sql)
|
172
|
+
id_ = result.scalar()
|
173
|
+
|
174
|
+
return id_
|
175
|
+
|
176
|
+
|
177
|
+
class DatabaseConnectionAsync(DatabaseBase):
|
178
|
+
"""
|
179
|
+
Asynchronous database connection type.
|
180
|
+
"""
|
181
|
+
|
182
|
+
|
183
|
+
def __init__(
|
184
|
+
self,
|
185
|
+
db: Database,
|
186
|
+
autocommit: bool
|
187
|
+
) -> None:
|
188
|
+
"""
|
189
|
+
Build instance attributes.
|
190
|
+
|
191
|
+
Parameters
|
192
|
+
----------
|
193
|
+
db : `DatabaseAsync` instance.
|
194
|
+
autocommit: Whether automatic commit execute.
|
195
|
+
"""
|
196
|
+
|
197
|
+
# Import.
|
198
|
+
from .rexec import DatabaseExecuteAsync
|
199
|
+
|
200
|
+
# Build.
|
201
|
+
self.db = db
|
202
|
+
self.autocommit = autocommit
|
203
|
+
self.execute = DatabaseExecuteAsync(self)
|
204
|
+
self.conn: AsyncConnection | None = None
|
205
|
+
self.begin: AsyncTransaction | None = None
|
121
206
|
|
122
207
|
|
123
|
-
|
124
|
-
def execute(self):
|
208
|
+
async def get_conn(self) -> AsyncConnection:
|
125
209
|
"""
|
126
|
-
|
210
|
+
Asynchronous get `Connection` instance.
|
127
211
|
|
128
212
|
Returns
|
129
213
|
-------
|
130
214
|
Instance.
|
131
215
|
"""
|
132
216
|
|
133
|
-
# Create
|
217
|
+
# Create.
|
218
|
+
if self.conn is None:
|
219
|
+
self.conn = await self.db.aengine.connect()
|
220
|
+
|
221
|
+
return self.conn
|
222
|
+
|
223
|
+
|
224
|
+
async def get_begin(self) -> AsyncTransaction:
|
225
|
+
"""
|
226
|
+
Asynchronous get `Transaction` instance.
|
227
|
+
|
228
|
+
Returns
|
229
|
+
-------
|
230
|
+
Instance.
|
231
|
+
"""
|
232
|
+
|
233
|
+
# Create.
|
134
234
|
if self.begin is None:
|
135
|
-
|
235
|
+
conn = await self.get_conn()
|
236
|
+
self.begin = await conn.begin()
|
136
237
|
|
137
|
-
return self.
|
238
|
+
return self.begin
|
138
239
|
|
139
240
|
|
140
|
-
|
141
|
-
def insert_id(self) -> int:
|
241
|
+
async def commit(self) -> None:
|
142
242
|
"""
|
143
|
-
|
243
|
+
Asynchronous commit cumulative executions.
|
244
|
+
"""
|
245
|
+
|
246
|
+
# Commit.
|
247
|
+
if self.begin is not None:
|
248
|
+
await self.begin.commit()
|
249
|
+
self.begin = None
|
250
|
+
|
251
|
+
|
252
|
+
async def rollback(self) -> None:
|
253
|
+
"""
|
254
|
+
Asynchronous rollback cumulative executions.
|
255
|
+
"""
|
256
|
+
|
257
|
+
# Rollback.
|
258
|
+
if self.begin is not None:
|
259
|
+
await self.begin.rollback()
|
260
|
+
self.begin = None
|
261
|
+
|
262
|
+
|
263
|
+
async def close(self) -> None:
|
264
|
+
"""
|
265
|
+
Asynchronous close database connection.
|
266
|
+
"""
|
267
|
+
|
268
|
+
# Close.
|
269
|
+
if self.begin is not None:
|
270
|
+
await self.begin.close()
|
271
|
+
self.begin = None
|
272
|
+
if self.conn is not None:
|
273
|
+
await self.conn.close()
|
274
|
+
self.conn = None
|
275
|
+
|
276
|
+
|
277
|
+
async def __aenter__(self) -> Self:
|
278
|
+
"""
|
279
|
+
Asynchronous enter syntax `async with`.
|
280
|
+
|
281
|
+
Returns
|
282
|
+
-------
|
283
|
+
Self.
|
284
|
+
"""
|
285
|
+
|
286
|
+
return self
|
287
|
+
|
288
|
+
|
289
|
+
async def __aexit__(
|
290
|
+
self,
|
291
|
+
exc_type: type[BaseException] | None,
|
292
|
+
*_
|
293
|
+
) -> None:
|
294
|
+
"""
|
295
|
+
Asynchronous exit syntax `async with`.
|
296
|
+
|
297
|
+
Parameters
|
298
|
+
----------
|
299
|
+
exc_type : Exception type.
|
300
|
+
"""
|
301
|
+
|
302
|
+
# Commit.
|
303
|
+
if exc_type is None:
|
304
|
+
await self.commit()
|
305
|
+
|
306
|
+
# Close.
|
307
|
+
else:
|
308
|
+
await self.close()
|
309
|
+
|
310
|
+
|
311
|
+
async def insert_id(self) -> int:
|
312
|
+
"""
|
313
|
+
Asynchronous return last self increasing ID.
|
144
314
|
|
145
315
|
Returns
|
146
316
|
-------
|
@@ -149,7 +319,7 @@ class DatabaseConnection(DatabaseBase):
|
|
149
319
|
|
150
320
|
# Get.
|
151
321
|
sql = 'SELECT LAST_INSERT_ID()'
|
152
|
-
result = self.execute(sql)
|
322
|
+
result = await self.execute(sql)
|
153
323
|
id_ = result.scalar()
|
154
324
|
|
155
325
|
return id_
|
reydb/rdb.py
CHANGED
@@ -9,10 +9,12 @@
|
|
9
9
|
"""
|
10
10
|
|
11
11
|
|
12
|
+
from typing import Literal, Final, overload
|
12
13
|
from urllib.parse import quote as urllib_quote
|
13
14
|
from pymysql.constants.CLIENT import MULTI_STATEMENTS
|
14
15
|
from sqlalchemy import create_engine as sqlalchemy_create_engine
|
15
16
|
from sqlalchemy.engine.base import Engine
|
17
|
+
from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine as sqlalchemy_create_async_engine
|
16
18
|
from reykit.rtext import join_data_text
|
17
19
|
|
18
20
|
from .rbase import DatabaseBase, extract_url
|
@@ -26,10 +28,6 @@ __all__ = (
|
|
26
28
|
class Database(DatabaseBase):
|
27
29
|
"""
|
28
30
|
Database type, based `MySQL`.
|
29
|
-
|
30
|
-
Attributes
|
31
|
-
----------
|
32
|
-
default_report : Whether default to report execution.
|
33
31
|
"""
|
34
32
|
|
35
33
|
default_report: bool = False
|
@@ -45,7 +43,7 @@ class Database(DatabaseBase):
|
|
45
43
|
pool_size: int = 5,
|
46
44
|
max_overflow: int = 10,
|
47
45
|
pool_timeout: float = 30.0,
|
48
|
-
pool_recycle: int | None =
|
46
|
+
pool_recycle: int | None = 3600,
|
49
47
|
**query: str
|
50
48
|
) -> None:
|
51
49
|
"""
|
@@ -62,10 +60,7 @@ class Database(DatabaseBase):
|
|
62
60
|
max_overflow : Number of connections `allowed overflow`.
|
63
61
|
pool_timeout : Number of seconds `wait create` connection.
|
64
62
|
pool_recycle : Number of seconds `recycle` connection.
|
65
|
-
- `None`:
|
66
|
-
When is remote server database, then is database variable `wait_timeout` value.
|
67
|
-
When is local database file, then is `-1`.
|
68
|
-
- `Literal[-1]`: No recycle.
|
63
|
+
- `None | Literal[-1]`: No recycle.
|
69
64
|
- `int`: Use this value.
|
70
65
|
query : Remote server database parameters.
|
71
66
|
"""
|
@@ -90,14 +85,8 @@ class Database(DatabaseBase):
|
|
90
85
|
self.query = query
|
91
86
|
|
92
87
|
# Create engine.
|
93
|
-
self.engine = self.__create_engine()
|
94
|
-
|
95
|
-
# Server recycle time.
|
96
|
-
if pool_recycle is None:
|
97
|
-
wait_timeout = self.variables['wait_timeout']
|
98
|
-
if wait_timeout is not None:
|
99
|
-
self.pool_recycle = int(wait_timeout)
|
100
|
-
self.engine.pool._recycle = self.pool_recycle
|
88
|
+
self.engine = self.__create_engine(False)
|
89
|
+
self.aengine = self.__create_engine(True)
|
101
90
|
|
102
91
|
|
103
92
|
@property
|
@@ -146,7 +135,10 @@ class Database(DatabaseBase):
|
|
146
135
|
|
147
136
|
# Generate URL.
|
148
137
|
password = urllib_quote(self.password)
|
149
|
-
|
138
|
+
if self.is_async:
|
139
|
+
url_ = f'mysql+aiomysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
|
140
|
+
else:
|
141
|
+
url_ = f'mysql+pymysql://{self.username}:{password}@{self.host}:{self.port}/{self.database}'
|
150
142
|
|
151
143
|
# Add Server parameter.
|
152
144
|
if self.query != {}:
|
@@ -161,10 +153,20 @@ class Database(DatabaseBase):
|
|
161
153
|
return url_
|
162
154
|
|
163
155
|
|
164
|
-
|
156
|
+
@overload
|
157
|
+
def __create_engine(self, is_async: Literal[False]) -> Engine: ...
|
158
|
+
|
159
|
+
@overload
|
160
|
+
def __create_engine(self, is_async: Literal[True]) -> AsyncEngine: ...
|
161
|
+
|
162
|
+
def __create_engine(self, is_async: bool) -> Engine | AsyncEngine:
|
165
163
|
"""
|
166
164
|
Create database `Engine` object.
|
167
165
|
|
166
|
+
Parameters
|
167
|
+
----------
|
168
|
+
is_async : Whether to use asynchronous engine.
|
169
|
+
|
168
170
|
Returns
|
169
171
|
-------
|
170
172
|
Engine object.
|
@@ -181,23 +183,35 @@ class Database(DatabaseBase):
|
|
181
183
|
}
|
182
184
|
|
183
185
|
# Create Engine.
|
184
|
-
|
186
|
+
if is_async:
|
187
|
+
engine = sqlalchemy_create_async_engine(**engine_params)
|
188
|
+
else:
|
189
|
+
engine = sqlalchemy_create_engine(**engine_params)
|
185
190
|
|
186
191
|
return engine
|
187
192
|
|
188
193
|
|
189
|
-
|
190
|
-
def count_conn(self) -> tuple[int, int]:
|
194
|
+
def __conn_count(self, is_async: bool) -> tuple[int, int]:
|
191
195
|
"""
|
192
196
|
Count number of keep open and allowed overflow connection.
|
193
197
|
|
198
|
+
Parameters
|
199
|
+
----------
|
200
|
+
is_async : Whether to use asynchronous engine.
|
201
|
+
|
194
202
|
Returns
|
195
203
|
-------
|
196
204
|
Number of keep open and allowed overflow connection.
|
197
205
|
"""
|
198
206
|
|
207
|
+
# Handle parameter.
|
208
|
+
if is_async:
|
209
|
+
engine = self.aengine
|
210
|
+
else:
|
211
|
+
engine = self.engine
|
212
|
+
|
199
213
|
# Count.
|
200
|
-
_overflow =
|
214
|
+
_overflow: int = engine.pool._overflow
|
201
215
|
if _overflow < 0:
|
202
216
|
keep_n = self.pool_size + _overflow
|
203
217
|
overflow_n = 0
|
@@ -208,6 +222,38 @@ class Database(DatabaseBase):
|
|
208
222
|
return keep_n, overflow_n
|
209
223
|
|
210
224
|
|
225
|
+
@property
|
226
|
+
def conn_count(self) -> tuple[int, int]:
|
227
|
+
"""
|
228
|
+
Count number of keep open and allowed overflow connection.
|
229
|
+
|
230
|
+
Returns
|
231
|
+
-------
|
232
|
+
Number of keep open and allowed overflow connection.
|
233
|
+
"""
|
234
|
+
|
235
|
+
# Count.
|
236
|
+
keep_n, overflow_n = self.__conn_count(False)
|
237
|
+
|
238
|
+
return keep_n, overflow_n
|
239
|
+
|
240
|
+
|
241
|
+
@property
|
242
|
+
def aconn_count(self) -> tuple[int, int]:
|
243
|
+
"""
|
244
|
+
Count number of keep open and allowed overflow asynchronous connection.
|
245
|
+
|
246
|
+
Returns
|
247
|
+
-------
|
248
|
+
Number of keep open and allowed overflow asynchronous connection.
|
249
|
+
"""
|
250
|
+
|
251
|
+
# Count.
|
252
|
+
keep_n, overflow_n = self.__conn_count(True)
|
253
|
+
|
254
|
+
return keep_n, overflow_n
|
255
|
+
|
256
|
+
|
211
257
|
def schema(self, filter_default: bool = True) -> dict[str, dict[str, list[str]]]:
|
212
258
|
"""
|
213
259
|
Get schemata of databases and tables and columns.
|
@@ -317,6 +363,45 @@ class Database(DatabaseBase):
|
|
317
363
|
return exec
|
318
364
|
|
319
365
|
|
366
|
+
def aconnect(self, autocommit: bool = False):
|
367
|
+
"""
|
368
|
+
Build `DatabaseConnectionAsync` instance.
|
369
|
+
|
370
|
+
Parameters
|
371
|
+
----------
|
372
|
+
autocommit: Whether automatic commit execute.
|
373
|
+
|
374
|
+
Returns
|
375
|
+
-------
|
376
|
+
Database connection instance.
|
377
|
+
"""
|
378
|
+
|
379
|
+
# Import.
|
380
|
+
from .rconn import DatabaseConnectionAsync
|
381
|
+
|
382
|
+
# Build.
|
383
|
+
conn = DatabaseConnectionAsync(self, autocommit)
|
384
|
+
|
385
|
+
return conn
|
386
|
+
|
387
|
+
|
388
|
+
@property
|
389
|
+
def aexecute(self):
|
390
|
+
"""
|
391
|
+
Build `DatabaseConnectionAsync` instance.
|
392
|
+
|
393
|
+
Returns
|
394
|
+
-------
|
395
|
+
Instance.
|
396
|
+
"""
|
397
|
+
|
398
|
+
# Build.
|
399
|
+
dbconn = self.aconnect(True)
|
400
|
+
exec = dbconn.execute
|
401
|
+
|
402
|
+
return exec
|
403
|
+
|
404
|
+
|
320
405
|
@property
|
321
406
|
def orm(self):
|
322
407
|
"""
|
@@ -546,7 +631,8 @@ class Database(DatabaseBase):
|
|
546
631
|
for key, value in self.__dict__.items()
|
547
632
|
if key not in filter_key
|
548
633
|
}
|
549
|
-
info['
|
634
|
+
info['conn_count'] = self.conn_count
|
635
|
+
info['aconn_count'] = self.aconn_count
|
550
636
|
text = join_data_text(info)
|
551
637
|
|
552
638
|
return text
|