datus-postgresql 0.1.2__tar.gz → 0.1.4__tar.gz
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.
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/PKG-INFO +1 -1
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/datus_postgresql/config.py +7 -2
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/datus_postgresql/connector.py +105 -22
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/pyproject.toml +1 -1
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/scripts/init_tpch_data.py +151 -15
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/conftest.py +2 -1
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/integration/conftest.py +152 -15
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/integration/test_integration.py +9 -4
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/integration/test_tpch.py +7 -1
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/unit/test_config.py +2 -1
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/unit/test_connector_unit.py +11 -5
- datus_postgresql-0.1.2/.gitignore +0 -140
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/README.md +0 -0
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/datus_postgresql/__init__.py +0 -0
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/datus_postgresql/handlers.py +0 -0
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/docker-compose.yml +0 -0
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/__init__.py +0 -0
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/integration/__init__.py +0 -0
- {datus_postgresql-0.1.2 → datus_postgresql-0.1.4}/tests/unit/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: datus-postgresql
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.4
|
|
4
4
|
Summary: PostgreSQL database adapter for Datus
|
|
5
5
|
Project-URL: Homepage, https://github.com/Datus-ai/datus-db-adapters
|
|
6
6
|
Project-URL: Repository, https://github.com/Datus-ai/datus-db-adapters
|
|
@@ -15,10 +15,15 @@ class PostgreSQLConfig(BaseModel):
|
|
|
15
15
|
host: str = Field(default="127.0.0.1", description="PostgreSQL server host")
|
|
16
16
|
port: int = Field(default=5432, description="PostgreSQL server port")
|
|
17
17
|
username: str = Field(..., description="PostgreSQL username")
|
|
18
|
-
password: str = Field(
|
|
18
|
+
password: str = Field(
|
|
19
|
+
default="",
|
|
20
|
+
description="PostgreSQL password",
|
|
21
|
+
json_schema_extra={"input_type": "password"},
|
|
22
|
+
)
|
|
19
23
|
database: Optional[str] = Field(default=None, description="Default database name")
|
|
20
24
|
schema_name: Optional[str] = Field(default="public", alias="schema", description="Default schema name")
|
|
21
25
|
sslmode: str = Field(
|
|
22
|
-
default="prefer",
|
|
26
|
+
default="prefer",
|
|
27
|
+
description="SSL mode (disable, allow, prefer, require, verify-ca, verify-full)",
|
|
23
28
|
)
|
|
24
29
|
timeout_seconds: int = Field(default=30, description="Connection timeout in seconds")
|
|
@@ -5,9 +5,18 @@
|
|
|
5
5
|
from typing import Any, Dict, List, Optional, Set, Union, override
|
|
6
6
|
from urllib.parse import quote_plus
|
|
7
7
|
|
|
8
|
-
from
|
|
9
|
-
from datus_sqlalchemy import SQLAlchemyConnector
|
|
8
|
+
from pandas import DataFrame
|
|
10
9
|
from pydantic import BaseModel, Field
|
|
10
|
+
from sqlalchemy import create_engine, text
|
|
11
|
+
|
|
12
|
+
from datus_db_core import (
|
|
13
|
+
TABLE_TYPE,
|
|
14
|
+
DatusDbException,
|
|
15
|
+
ErrorCode,
|
|
16
|
+
get_logger,
|
|
17
|
+
list_to_in_str,
|
|
18
|
+
)
|
|
19
|
+
from datus_sqlalchemy import SQLAlchemyConnector
|
|
11
20
|
|
|
12
21
|
from .config import PostgreSQLConfig
|
|
13
22
|
|
|
@@ -76,7 +85,11 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
76
85
|
f"{database}?sslmode={config.sslmode}"
|
|
77
86
|
)
|
|
78
87
|
|
|
79
|
-
super().__init__(
|
|
88
|
+
super().__init__(
|
|
89
|
+
connection_string,
|
|
90
|
+
dialect="postgresql",
|
|
91
|
+
timeout_seconds=config.timeout_seconds,
|
|
92
|
+
)
|
|
80
93
|
self.database_name = database
|
|
81
94
|
self.schema_name = config.schema_name or "public"
|
|
82
95
|
|
|
@@ -90,7 +103,13 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
90
103
|
@override
|
|
91
104
|
def _sys_schemas(self) -> Set[str]:
|
|
92
105
|
"""System schemas to filter out."""
|
|
93
|
-
return {
|
|
106
|
+
return {
|
|
107
|
+
"pg_catalog",
|
|
108
|
+
"information_schema",
|
|
109
|
+
"pg_toast",
|
|
110
|
+
"pg_temp_1",
|
|
111
|
+
"pg_toast_temp_1",
|
|
112
|
+
}
|
|
94
113
|
|
|
95
114
|
# ==================== Utility Methods ====================
|
|
96
115
|
|
|
@@ -100,6 +119,33 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
100
119
|
escaped = identifier.replace('"', '""')
|
|
101
120
|
return f'"{escaped}"'
|
|
102
121
|
|
|
122
|
+
def _build_connection_string(self, database_name: str) -> str:
|
|
123
|
+
"""Build a PostgreSQL connection string for a given database."""
|
|
124
|
+
encoded_username = quote_plus(self.username) if self.username else ""
|
|
125
|
+
encoded_password = quote_plus(self.password) if self.password else ""
|
|
126
|
+
return (
|
|
127
|
+
f"postgresql+psycopg2://{encoded_username}:{encoded_password}"
|
|
128
|
+
f"@{self.host}:{self.port}/{database_name}?sslmode={self.config.sslmode}"
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def _execute_on_database(self, sql: str, database_name: str) -> DataFrame:
|
|
132
|
+
"""Execute a query on a specific database using a temporary connection.
|
|
133
|
+
|
|
134
|
+
Thread-safe: creates an isolated connection without mutating self.
|
|
135
|
+
"""
|
|
136
|
+
if database_name == self.database_name:
|
|
137
|
+
return self._execute_pandas(sql)
|
|
138
|
+
|
|
139
|
+
conn_str = self._build_connection_string(database_name)
|
|
140
|
+
engine = create_engine(conn_str)
|
|
141
|
+
try:
|
|
142
|
+
with engine.connect() as conn:
|
|
143
|
+
result = conn.execute(text(sql))
|
|
144
|
+
rows = [row._asdict() for row in result.fetchall()]
|
|
145
|
+
return DataFrame(rows)
|
|
146
|
+
finally:
|
|
147
|
+
engine.dispose()
|
|
148
|
+
|
|
103
149
|
# ==================== Metadata Retrieval ====================
|
|
104
150
|
|
|
105
151
|
def _get_metadata(
|
|
@@ -122,13 +168,15 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
122
168
|
List of metadata dictionaries
|
|
123
169
|
"""
|
|
124
170
|
self.connect()
|
|
171
|
+
database_name = database_name or self.database_name
|
|
125
172
|
schema_name = schema_name or self.schema_name
|
|
126
173
|
|
|
127
174
|
# Get metadata configuration
|
|
128
175
|
metadata_config = _get_metadata_config(table_type)
|
|
129
176
|
|
|
130
177
|
if table_type == "mv":
|
|
131
|
-
#
|
|
178
|
+
# pg_matviews is scoped to the current database connection.
|
|
179
|
+
# Use a temporary connection if a different database is requested (thread-safe).
|
|
132
180
|
if schema_name:
|
|
133
181
|
where = f"schemaname = '{schema_name}'"
|
|
134
182
|
else:
|
|
@@ -139,8 +187,9 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
139
187
|
FROM pg_matviews
|
|
140
188
|
WHERE {where}
|
|
141
189
|
"""
|
|
190
|
+
query_result = self._execute_on_database(query, database_name)
|
|
142
191
|
else:
|
|
143
|
-
# Tables and views use information_schema
|
|
192
|
+
# Tables and views use information_schema (supports table_catalog filter)
|
|
144
193
|
if schema_name:
|
|
145
194
|
where = f"table_schema = '{schema_name}'"
|
|
146
195
|
else:
|
|
@@ -154,10 +203,9 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
154
203
|
query = f"""
|
|
155
204
|
SELECT table_schema, table_name
|
|
156
205
|
FROM information_schema.{metadata_config.info_table}
|
|
157
|
-
WHERE {where} {type_filter}
|
|
206
|
+
WHERE table_catalog = '{database_name}' AND {where} {type_filter}
|
|
158
207
|
"""
|
|
159
|
-
|
|
160
|
-
query_result = self._execute_pandas(query)
|
|
208
|
+
query_result = self._execute_pandas(query)
|
|
161
209
|
|
|
162
210
|
# Format results
|
|
163
211
|
result = []
|
|
@@ -168,7 +216,7 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
168
216
|
{
|
|
169
217
|
"identifier": self.identifier(schema_name=schema, table_name=tb_name),
|
|
170
218
|
"catalog_name": "",
|
|
171
|
-
"database_name":
|
|
219
|
+
"database_name": database_name,
|
|
172
220
|
"schema_name": schema,
|
|
173
221
|
"table_name": tb_name,
|
|
174
222
|
"table_type": table_type,
|
|
@@ -307,7 +355,11 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
307
355
|
|
|
308
356
|
@override
|
|
309
357
|
def get_tables_with_ddl(
|
|
310
|
-
self,
|
|
358
|
+
self,
|
|
359
|
+
catalog_name: str = "",
|
|
360
|
+
database_name: str = "",
|
|
361
|
+
schema_name: str = "",
|
|
362
|
+
tables: Optional[List[str]] = None,
|
|
311
363
|
) -> List[Dict[str, str]]:
|
|
312
364
|
"""Get tables with DDL statements."""
|
|
313
365
|
return self._get_objects_with_ddl("table", tables, catalog_name, database_name, schema_name)
|
|
@@ -321,7 +373,11 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
321
373
|
|
|
322
374
|
@override
|
|
323
375
|
def get_schema(
|
|
324
|
-
self,
|
|
376
|
+
self,
|
|
377
|
+
catalog_name: str = "",
|
|
378
|
+
database_name: str = "",
|
|
379
|
+
schema_name: str = "",
|
|
380
|
+
table_name: str = "",
|
|
325
381
|
) -> List[Dict[str, Any]]:
|
|
326
382
|
"""
|
|
327
383
|
Get table schema using INFORMATION_SCHEMA.
|
|
@@ -338,6 +394,7 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
338
394
|
if not table_name:
|
|
339
395
|
return []
|
|
340
396
|
|
|
397
|
+
database_name = database_name or self.database_name
|
|
341
398
|
schema_name = schema_name or self.schema_name
|
|
342
399
|
|
|
343
400
|
# Use INFORMATION_SCHEMA to get schema with comments
|
|
@@ -364,7 +421,8 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
364
421
|
ON st.schemaname = c.table_schema AND st.relname = c.table_name
|
|
365
422
|
LEFT JOIN pg_catalog.pg_description pgd
|
|
366
423
|
ON pgd.objoid = st.relid AND pgd.objsubid = c.ordinal_position
|
|
367
|
-
WHERE c.
|
|
424
|
+
WHERE c.table_catalog = '{database_name}'
|
|
425
|
+
AND c.table_schema = '{schema_name}'
|
|
368
426
|
AND c.table_name = '{table_name}'
|
|
369
427
|
ORDER BY c.ordinal_position
|
|
370
428
|
"""
|
|
@@ -403,7 +461,8 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
403
461
|
@override
|
|
404
462
|
def get_schemas(self, catalog_name: str = "", database_name: str = "", include_sys: bool = False) -> List[str]:
|
|
405
463
|
"""Get list of schemas in the current database."""
|
|
406
|
-
|
|
464
|
+
database_name = database_name or self.database_name
|
|
465
|
+
sql = f"SELECT schema_name FROM information_schema.schemata WHERE catalog_name = '{database_name}'"
|
|
407
466
|
result = self._execute_pandas(sql)
|
|
408
467
|
schemas = result["schema_name"].tolist()
|
|
409
468
|
|
|
@@ -422,11 +481,17 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
422
481
|
|
|
423
482
|
@override
|
|
424
483
|
def do_switch_context(self, catalog_name: str = "", database_name: str = "", schema_name: str = ""):
|
|
425
|
-
"""Switch schema context
|
|
484
|
+
"""Switch database/schema context.
|
|
426
485
|
|
|
427
|
-
|
|
428
|
-
|
|
486
|
+
PostgreSQL requires reconnection to switch databases.
|
|
487
|
+
Schema switching only updates self.schema_name since all queries
|
|
488
|
+
use explicit schema qualification via full_name().
|
|
429
489
|
"""
|
|
490
|
+
if database_name and database_name != self.database_name:
|
|
491
|
+
self.connection_string = self._build_connection_string(database_name)
|
|
492
|
+
self.close()
|
|
493
|
+
self.connect()
|
|
494
|
+
self.database_name = database_name
|
|
430
495
|
if schema_name:
|
|
431
496
|
self.schema_name = schema_name
|
|
432
497
|
|
|
@@ -477,7 +542,7 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
477
542
|
return result
|
|
478
543
|
|
|
479
544
|
# Otherwise get metadata and query all tables
|
|
480
|
-
metadata = self._get_metadata(table_type, "",
|
|
545
|
+
metadata = self._get_metadata(table_type, "", database_name, schema_name)
|
|
481
546
|
for meta in metadata:
|
|
482
547
|
full_name = self.full_name(schema_name=meta["schema_name"], table_name=meta["table_name"])
|
|
483
548
|
sql = f"SELECT * FROM {full_name} LIMIT {top_n}"
|
|
@@ -499,28 +564,46 @@ class PostgreSQLConnector(SQLAlchemyConnector):
|
|
|
499
564
|
|
|
500
565
|
@override
|
|
501
566
|
def identifier(
|
|
502
|
-
self,
|
|
567
|
+
self,
|
|
568
|
+
catalog_name: str = "",
|
|
569
|
+
database_name: str = "",
|
|
570
|
+
schema_name: str = "",
|
|
571
|
+
table_name: str = "",
|
|
503
572
|
) -> str:
|
|
504
573
|
"""Generate a unique identifier for a table."""
|
|
574
|
+
database_name = database_name or self.database_name
|
|
505
575
|
schema_name = schema_name or self.schema_name
|
|
576
|
+
if database_name and schema_name:
|
|
577
|
+
return f"{database_name}.{schema_name}.{table_name}"
|
|
506
578
|
if schema_name:
|
|
507
579
|
return f"{schema_name}.{table_name}"
|
|
508
580
|
return table_name
|
|
509
581
|
|
|
510
582
|
@override
|
|
511
583
|
def full_name(
|
|
512
|
-
self,
|
|
584
|
+
self,
|
|
585
|
+
catalog_name: str = "",
|
|
586
|
+
database_name: str = "",
|
|
587
|
+
schema_name: str = "",
|
|
588
|
+
table_name: str = "",
|
|
513
589
|
) -> str:
|
|
514
590
|
"""Build fully-qualified table name."""
|
|
591
|
+
database_name = database_name or self.database_name
|
|
515
592
|
schema_name = schema_name or self.schema_name
|
|
593
|
+
if database_name and schema_name:
|
|
594
|
+
return f"{self._quote_identifier(database_name)}.{self._quote_identifier(schema_name)}.{self._quote_identifier(table_name)}"
|
|
516
595
|
if schema_name:
|
|
517
596
|
return f"{self._quote_identifier(schema_name)}.{self._quote_identifier(table_name)}"
|
|
518
597
|
return self._quote_identifier(table_name)
|
|
519
598
|
|
|
520
599
|
@override
|
|
521
600
|
def _reset_filter_tables(
|
|
522
|
-
self,
|
|
601
|
+
self,
|
|
602
|
+
tables: Optional[List[str]] = None,
|
|
603
|
+
catalog_name: str = "",
|
|
604
|
+
database_name: str = "",
|
|
605
|
+
schema_name: str = "",
|
|
523
606
|
) -> List[str]:
|
|
524
607
|
"""Reset filter tables with full names."""
|
|
525
608
|
schema_name = schema_name or self.schema_name
|
|
526
|
-
return super()._reset_filter_tables(tables, "",
|
|
609
|
+
return super()._reset_filter_tables(tables, "", database_name, schema_name)
|
|
@@ -104,7 +104,12 @@ TPCH_DATA = {
|
|
|
104
104
|
],
|
|
105
105
|
"tpch_nation": [
|
|
106
106
|
(0, "ALGERIA", 0, " haggle. carefully final deposits detect slyly agai"),
|
|
107
|
-
(
|
|
107
|
+
(
|
|
108
|
+
1,
|
|
109
|
+
"ARGENTINA",
|
|
110
|
+
1,
|
|
111
|
+
"al foxes promise slyly according to the regular accounts.",
|
|
112
|
+
),
|
|
108
113
|
(2, "BRAZIL", 1, "y alongside of the pending deposits."),
|
|
109
114
|
(3, "CANADA", 1, "eas hang ironic, silent packages."),
|
|
110
115
|
(4, "EGYPT", 4, "y above the carefully unusual theodolites."),
|
|
@@ -118,7 +123,12 @@ TPCH_DATA = {
|
|
|
118
123
|
(12, "JAPAN", 2, "ously. final, express gifts cajole a"),
|
|
119
124
|
(13, "JORDAN", 4, "ic deposits are blithely about the carefully regular pa"),
|
|
120
125
|
(14, "KENYA", 0, " pending excuses haggle furiously deposits."),
|
|
121
|
-
(
|
|
126
|
+
(
|
|
127
|
+
15,
|
|
128
|
+
"MOROCCO",
|
|
129
|
+
0,
|
|
130
|
+
"rns. blithely bold courts among the closely regular packages",
|
|
131
|
+
),
|
|
122
132
|
(16, "MOZAMBIQUE", 0, "s. ironic, unusual asymptotes wake blithely r"),
|
|
123
133
|
(17, "PERU", 1, "platelets. blithely pending dependencies use fluffily"),
|
|
124
134
|
(18, "CHINA", 2, "c dependencies. furiously express notornis sleep slyly"),
|
|
@@ -139,7 +149,15 @@ TPCH_DATA = {
|
|
|
139
149
|
5755.94,
|
|
140
150
|
"each slyly above the careful",
|
|
141
151
|
),
|
|
142
|
-
(
|
|
152
|
+
(
|
|
153
|
+
2,
|
|
154
|
+
"Supplier#000000002",
|
|
155
|
+
"89eJ5ksX3ImxJQBvxObC,",
|
|
156
|
+
5,
|
|
157
|
+
"15-679-861-2259",
|
|
158
|
+
4032.68,
|
|
159
|
+
" slyly bold instructions.",
|
|
160
|
+
),
|
|
143
161
|
(
|
|
144
162
|
3,
|
|
145
163
|
"Supplier#000000003",
|
|
@@ -158,7 +176,15 @@ TPCH_DATA = {
|
|
|
158
176
|
4641.08,
|
|
159
177
|
"riously even requests above the exp",
|
|
160
178
|
),
|
|
161
|
-
(
|
|
179
|
+
(
|
|
180
|
+
5,
|
|
181
|
+
"Supplier#000000005",
|
|
182
|
+
"Gcdm2rJRzl5qlTVzc",
|
|
183
|
+
11,
|
|
184
|
+
"21-151-690-3663",
|
|
185
|
+
-531.44,
|
|
186
|
+
". slyly regular pinto beans t",
|
|
187
|
+
),
|
|
162
188
|
],
|
|
163
189
|
"tpch_customer": [
|
|
164
190
|
(
|
|
@@ -263,7 +289,17 @@ TPCH_DATA = {
|
|
|
263
289
|
),
|
|
264
290
|
],
|
|
265
291
|
"tpch_orders": [
|
|
266
|
-
(
|
|
292
|
+
(
|
|
293
|
+
1,
|
|
294
|
+
1,
|
|
295
|
+
"O",
|
|
296
|
+
173665.47,
|
|
297
|
+
"1996-01-02",
|
|
298
|
+
"5-LOW",
|
|
299
|
+
"Clerk#000000951",
|
|
300
|
+
0,
|
|
301
|
+
"nstructions sleep furiously among",
|
|
302
|
+
),
|
|
267
303
|
(
|
|
268
304
|
2,
|
|
269
305
|
2,
|
|
@@ -275,9 +311,39 @@ TPCH_DATA = {
|
|
|
275
311
|
0,
|
|
276
312
|
" foxes. pending accounts at the pending",
|
|
277
313
|
),
|
|
278
|
-
(
|
|
279
|
-
|
|
280
|
-
|
|
314
|
+
(
|
|
315
|
+
3,
|
|
316
|
+
3,
|
|
317
|
+
"F",
|
|
318
|
+
193846.25,
|
|
319
|
+
"1993-10-14",
|
|
320
|
+
"5-LOW",
|
|
321
|
+
"Clerk#000000955",
|
|
322
|
+
0,
|
|
323
|
+
"sly final accounts boost.",
|
|
324
|
+
),
|
|
325
|
+
(
|
|
326
|
+
4,
|
|
327
|
+
4,
|
|
328
|
+
"O",
|
|
329
|
+
32151.78,
|
|
330
|
+
"1995-10-11",
|
|
331
|
+
"5-LOW",
|
|
332
|
+
"Clerk#000000124",
|
|
333
|
+
0,
|
|
334
|
+
"sits. slyly regular warthogs cajole.",
|
|
335
|
+
),
|
|
336
|
+
(
|
|
337
|
+
5,
|
|
338
|
+
5,
|
|
339
|
+
"F",
|
|
340
|
+
144659.20,
|
|
341
|
+
"1994-07-30",
|
|
342
|
+
"5-LOW",
|
|
343
|
+
"Clerk#000000925",
|
|
344
|
+
0,
|
|
345
|
+
"quickly. bold deposits sleep slyly.",
|
|
346
|
+
),
|
|
281
347
|
(
|
|
282
348
|
6,
|
|
283
349
|
6,
|
|
@@ -289,9 +355,39 @@ TPCH_DATA = {
|
|
|
289
355
|
0,
|
|
290
356
|
"ggle. special, final requests are against the furiously",
|
|
291
357
|
),
|
|
292
|
-
(
|
|
293
|
-
|
|
294
|
-
|
|
358
|
+
(
|
|
359
|
+
7,
|
|
360
|
+
7,
|
|
361
|
+
"O",
|
|
362
|
+
252004.18,
|
|
363
|
+
"1996-01-10",
|
|
364
|
+
"2-HIGH",
|
|
365
|
+
"Clerk#000000470",
|
|
366
|
+
0,
|
|
367
|
+
"ly special requests",
|
|
368
|
+
),
|
|
369
|
+
(
|
|
370
|
+
32,
|
|
371
|
+
8,
|
|
372
|
+
"O",
|
|
373
|
+
208660.75,
|
|
374
|
+
"1995-07-16",
|
|
375
|
+
"2-HIGH",
|
|
376
|
+
"Clerk#000000616",
|
|
377
|
+
0,
|
|
378
|
+
"ise blithely bold, regular requests.",
|
|
379
|
+
),
|
|
380
|
+
(
|
|
381
|
+
33,
|
|
382
|
+
9,
|
|
383
|
+
"F",
|
|
384
|
+
163243.98,
|
|
385
|
+
"1993-10-27",
|
|
386
|
+
"3-MEDIUM",
|
|
387
|
+
"Clerk#000000409",
|
|
388
|
+
0,
|
|
389
|
+
"uriously. furiously final request",
|
|
390
|
+
),
|
|
295
391
|
(
|
|
296
392
|
34,
|
|
297
393
|
10,
|
|
@@ -314,10 +410,50 @@ TPCH_DATA = {
|
|
|
314
410
|
0,
|
|
315
411
|
"zzle. carefully enticing deposits nag furio",
|
|
316
412
|
),
|
|
317
|
-
(
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
413
|
+
(
|
|
414
|
+
36,
|
|
415
|
+
2,
|
|
416
|
+
"O",
|
|
417
|
+
38988.98,
|
|
418
|
+
"1995-11-03",
|
|
419
|
+
"1-URGENT",
|
|
420
|
+
"Clerk#000000358",
|
|
421
|
+
0,
|
|
422
|
+
" quick packages are blithely.",
|
|
423
|
+
),
|
|
424
|
+
(
|
|
425
|
+
37,
|
|
426
|
+
3,
|
|
427
|
+
"F",
|
|
428
|
+
131896.48,
|
|
429
|
+
"1992-06-03",
|
|
430
|
+
"3-MEDIUM",
|
|
431
|
+
"Clerk#000000456",
|
|
432
|
+
0,
|
|
433
|
+
"kly regular pinto beans.",
|
|
434
|
+
),
|
|
435
|
+
(
|
|
436
|
+
38,
|
|
437
|
+
4,
|
|
438
|
+
"O",
|
|
439
|
+
46366.56,
|
|
440
|
+
"1996-08-21",
|
|
441
|
+
"4-NOT SPECIFIED",
|
|
442
|
+
"Clerk#000000604",
|
|
443
|
+
0,
|
|
444
|
+
"haggle blithely.",
|
|
445
|
+
),
|
|
446
|
+
(
|
|
447
|
+
39,
|
|
448
|
+
5,
|
|
449
|
+
"O",
|
|
450
|
+
219707.84,
|
|
451
|
+
"1996-09-20",
|
|
452
|
+
"3-MEDIUM",
|
|
453
|
+
"Clerk#000000659",
|
|
454
|
+
0,
|
|
455
|
+
"ole express, ironic requests:",
|
|
456
|
+
),
|
|
321
457
|
],
|
|
322
458
|
}
|
|
323
459
|
|
|
@@ -6,5 +6,6 @@
|
|
|
6
6
|
def pytest_configure(config):
|
|
7
7
|
"""Configure custom markers."""
|
|
8
8
|
config.addinivalue_line(
|
|
9
|
-
"markers",
|
|
9
|
+
"markers",
|
|
10
|
+
"integration: marks tests as integration tests (deselect with '-m \"not integration\"')",
|
|
10
11
|
)
|
|
@@ -6,6 +6,7 @@ import os
|
|
|
6
6
|
from typing import Generator
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
+
|
|
9
10
|
from datus_postgresql import PostgreSQLConfig, PostgreSQLConnector
|
|
10
11
|
|
|
11
12
|
# ---------------------------------------------------------------------------
|
|
@@ -83,7 +84,12 @@ TPCH_DATA = {
|
|
|
83
84
|
],
|
|
84
85
|
"tpch_nation": [
|
|
85
86
|
(0, "ALGERIA", 0, " haggle. carefully final deposits detect slyly agai"),
|
|
86
|
-
(
|
|
87
|
+
(
|
|
88
|
+
1,
|
|
89
|
+
"ARGENTINA",
|
|
90
|
+
1,
|
|
91
|
+
"al foxes promise slyly according to the regular accounts.",
|
|
92
|
+
),
|
|
87
93
|
(2, "BRAZIL", 1, "y alongside of the pending deposits."),
|
|
88
94
|
(3, "CANADA", 1, "eas hang ironic, silent packages."),
|
|
89
95
|
(4, "EGYPT", 4, "y above the carefully unusual theodolites."),
|
|
@@ -97,7 +103,12 @@ TPCH_DATA = {
|
|
|
97
103
|
(12, "JAPAN", 2, "ously. final, express gifts cajole a"),
|
|
98
104
|
(13, "JORDAN", 4, "ic deposits are blithely about the carefully regular pa"),
|
|
99
105
|
(14, "KENYA", 0, " pending excuses haggle furiously deposits."),
|
|
100
|
-
(
|
|
106
|
+
(
|
|
107
|
+
15,
|
|
108
|
+
"MOROCCO",
|
|
109
|
+
0,
|
|
110
|
+
"rns. blithely bold courts among the closely regular packages",
|
|
111
|
+
),
|
|
101
112
|
(16, "MOZAMBIQUE", 0, "s. ironic, unusual asymptotes wake blithely r"),
|
|
102
113
|
(17, "PERU", 1, "platelets. blithely pending dependencies use fluffily"),
|
|
103
114
|
(18, "CHINA", 2, "c dependencies. furiously express notornis sleep slyly"),
|
|
@@ -118,7 +129,15 @@ TPCH_DATA = {
|
|
|
118
129
|
5755.94,
|
|
119
130
|
"each slyly above the careful",
|
|
120
131
|
),
|
|
121
|
-
(
|
|
132
|
+
(
|
|
133
|
+
2,
|
|
134
|
+
"Supplier#000000002",
|
|
135
|
+
"89eJ5ksX3ImxJQBvxObC,",
|
|
136
|
+
5,
|
|
137
|
+
"15-679-861-2259",
|
|
138
|
+
4032.68,
|
|
139
|
+
" slyly bold instructions.",
|
|
140
|
+
),
|
|
122
141
|
(
|
|
123
142
|
3,
|
|
124
143
|
"Supplier#000000003",
|
|
@@ -137,7 +156,15 @@ TPCH_DATA = {
|
|
|
137
156
|
4641.08,
|
|
138
157
|
"riously even requests above the exp",
|
|
139
158
|
),
|
|
140
|
-
(
|
|
159
|
+
(
|
|
160
|
+
5,
|
|
161
|
+
"Supplier#000000005",
|
|
162
|
+
"Gcdm2rJRzl5qlTVzc",
|
|
163
|
+
11,
|
|
164
|
+
"21-151-690-3663",
|
|
165
|
+
-531.44,
|
|
166
|
+
". slyly regular pinto beans t",
|
|
167
|
+
),
|
|
141
168
|
],
|
|
142
169
|
"tpch_customer": [
|
|
143
170
|
(
|
|
@@ -242,7 +269,17 @@ TPCH_DATA = {
|
|
|
242
269
|
),
|
|
243
270
|
],
|
|
244
271
|
"tpch_orders": [
|
|
245
|
-
(
|
|
272
|
+
(
|
|
273
|
+
1,
|
|
274
|
+
1,
|
|
275
|
+
"O",
|
|
276
|
+
173665.47,
|
|
277
|
+
"1996-01-02",
|
|
278
|
+
"5-LOW",
|
|
279
|
+
"Clerk#000000951",
|
|
280
|
+
0,
|
|
281
|
+
"nstructions sleep furiously among",
|
|
282
|
+
),
|
|
246
283
|
(
|
|
247
284
|
2,
|
|
248
285
|
2,
|
|
@@ -254,9 +291,39 @@ TPCH_DATA = {
|
|
|
254
291
|
0,
|
|
255
292
|
" foxes. pending accounts at the pending",
|
|
256
293
|
),
|
|
257
|
-
(
|
|
258
|
-
|
|
259
|
-
|
|
294
|
+
(
|
|
295
|
+
3,
|
|
296
|
+
3,
|
|
297
|
+
"F",
|
|
298
|
+
193846.25,
|
|
299
|
+
"1993-10-14",
|
|
300
|
+
"5-LOW",
|
|
301
|
+
"Clerk#000000955",
|
|
302
|
+
0,
|
|
303
|
+
"sly final accounts boost.",
|
|
304
|
+
),
|
|
305
|
+
(
|
|
306
|
+
4,
|
|
307
|
+
4,
|
|
308
|
+
"O",
|
|
309
|
+
32151.78,
|
|
310
|
+
"1995-10-11",
|
|
311
|
+
"5-LOW",
|
|
312
|
+
"Clerk#000000124",
|
|
313
|
+
0,
|
|
314
|
+
"sits. slyly regular warthogs cajole.",
|
|
315
|
+
),
|
|
316
|
+
(
|
|
317
|
+
5,
|
|
318
|
+
5,
|
|
319
|
+
"F",
|
|
320
|
+
144659.20,
|
|
321
|
+
"1994-07-30",
|
|
322
|
+
"5-LOW",
|
|
323
|
+
"Clerk#000000925",
|
|
324
|
+
0,
|
|
325
|
+
"quickly. bold deposits sleep slyly.",
|
|
326
|
+
),
|
|
260
327
|
(
|
|
261
328
|
6,
|
|
262
329
|
6,
|
|
@@ -268,9 +335,39 @@ TPCH_DATA = {
|
|
|
268
335
|
0,
|
|
269
336
|
"ggle. special, final requests are against the furiously",
|
|
270
337
|
),
|
|
271
|
-
(
|
|
272
|
-
|
|
273
|
-
|
|
338
|
+
(
|
|
339
|
+
7,
|
|
340
|
+
7,
|
|
341
|
+
"O",
|
|
342
|
+
252004.18,
|
|
343
|
+
"1996-01-10",
|
|
344
|
+
"2-HIGH",
|
|
345
|
+
"Clerk#000000470",
|
|
346
|
+
0,
|
|
347
|
+
"ly special requests",
|
|
348
|
+
),
|
|
349
|
+
(
|
|
350
|
+
32,
|
|
351
|
+
8,
|
|
352
|
+
"O",
|
|
353
|
+
208660.75,
|
|
354
|
+
"1995-07-16",
|
|
355
|
+
"2-HIGH",
|
|
356
|
+
"Clerk#000000616",
|
|
357
|
+
0,
|
|
358
|
+
"ise blithely bold, regular requests.",
|
|
359
|
+
),
|
|
360
|
+
(
|
|
361
|
+
33,
|
|
362
|
+
9,
|
|
363
|
+
"F",
|
|
364
|
+
163243.98,
|
|
365
|
+
"1993-10-27",
|
|
366
|
+
"3-MEDIUM",
|
|
367
|
+
"Clerk#000000409",
|
|
368
|
+
0,
|
|
369
|
+
"uriously. furiously final request",
|
|
370
|
+
),
|
|
274
371
|
(
|
|
275
372
|
34,
|
|
276
373
|
10,
|
|
@@ -293,10 +390,50 @@ TPCH_DATA = {
|
|
|
293
390
|
0,
|
|
294
391
|
"zzle. carefully enticing deposits nag furio",
|
|
295
392
|
),
|
|
296
|
-
(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
393
|
+
(
|
|
394
|
+
36,
|
|
395
|
+
2,
|
|
396
|
+
"O",
|
|
397
|
+
38988.98,
|
|
398
|
+
"1995-11-03",
|
|
399
|
+
"1-URGENT",
|
|
400
|
+
"Clerk#000000358",
|
|
401
|
+
0,
|
|
402
|
+
" quick packages are blithely.",
|
|
403
|
+
),
|
|
404
|
+
(
|
|
405
|
+
37,
|
|
406
|
+
3,
|
|
407
|
+
"F",
|
|
408
|
+
131896.48,
|
|
409
|
+
"1992-06-03",
|
|
410
|
+
"3-MEDIUM",
|
|
411
|
+
"Clerk#000000456",
|
|
412
|
+
0,
|
|
413
|
+
"kly regular pinto beans.",
|
|
414
|
+
),
|
|
415
|
+
(
|
|
416
|
+
38,
|
|
417
|
+
4,
|
|
418
|
+
"O",
|
|
419
|
+
46366.56,
|
|
420
|
+
"1996-08-21",
|
|
421
|
+
"4-NOT SPECIFIED",
|
|
422
|
+
"Clerk#000000604",
|
|
423
|
+
0,
|
|
424
|
+
"haggle blithely.",
|
|
425
|
+
),
|
|
426
|
+
(
|
|
427
|
+
39,
|
|
428
|
+
5,
|
|
429
|
+
"O",
|
|
430
|
+
219707.84,
|
|
431
|
+
"1996-09-20",
|
|
432
|
+
"3-MEDIUM",
|
|
433
|
+
"Clerk#000000659",
|
|
434
|
+
0,
|
|
435
|
+
"ole express, ironic requests:",
|
|
436
|
+
),
|
|
300
437
|
],
|
|
301
438
|
}
|
|
302
439
|
|
|
@@ -6,6 +6,7 @@ import os
|
|
|
6
6
|
import uuid
|
|
7
7
|
|
|
8
8
|
import pytest
|
|
9
|
+
|
|
9
10
|
from datus_postgresql import PostgreSQLConfig, PostgreSQLConnector
|
|
10
11
|
|
|
11
12
|
# ==================== Connection Tests ====================
|
|
@@ -307,7 +308,8 @@ def test_execute_insert(connector: PostgreSQLConnector, config: PostgreSQLConfig
|
|
|
307
308
|
|
|
308
309
|
# Verify
|
|
309
310
|
query_result = connector.execute(
|
|
310
|
-
{"sql_query": f"SELECT id, name FROM {table_name} ORDER BY id"},
|
|
311
|
+
{"sql_query": f"SELECT id, name FROM {table_name} ORDER BY id"},
|
|
312
|
+
result_format="list",
|
|
311
313
|
)
|
|
312
314
|
assert len(query_result.sql_return) == 2
|
|
313
315
|
assert query_result.sql_return[0]["name"] == "Alice"
|
|
@@ -342,7 +344,8 @@ def test_execute_update(connector: PostgreSQLConnector, config: PostgreSQLConfig
|
|
|
342
344
|
|
|
343
345
|
# Verify
|
|
344
346
|
query_result = connector.execute(
|
|
345
|
-
{"sql_query": f"SELECT name FROM {table_name} WHERE id = 1"},
|
|
347
|
+
{"sql_query": f"SELECT name FROM {table_name} WHERE id = 1"},
|
|
348
|
+
result_format="list",
|
|
346
349
|
)
|
|
347
350
|
assert query_result.sql_return == [{"name": "Alice Updated"}]
|
|
348
351
|
finally:
|
|
@@ -404,8 +407,9 @@ def test_exception_on_nonexistent_table(connector: PostgreSQLConnector):
|
|
|
404
407
|
@pytest.mark.integration
|
|
405
408
|
def test_full_name_with_schema(connector: PostgreSQLConnector):
|
|
406
409
|
"""Test full_name with schema."""
|
|
410
|
+
db = connector.database_name
|
|
407
411
|
full_name = connector.full_name(schema_name="myschema", table_name="mytable")
|
|
408
|
-
assert full_name == '"myschema"."mytable"'
|
|
412
|
+
assert full_name == f'"{db}"."myschema"."mytable"'
|
|
409
413
|
|
|
410
414
|
|
|
411
415
|
@pytest.mark.integration
|
|
@@ -419,5 +423,6 @@ def test_full_name_with_default_schema(connector: PostgreSQLConnector):
|
|
|
419
423
|
@pytest.mark.integration
|
|
420
424
|
def test_identifier(connector: PostgreSQLConnector):
|
|
421
425
|
"""Test identifier generation."""
|
|
426
|
+
db = connector.database_name
|
|
422
427
|
identifier = connector.identifier(schema_name="myschema", table_name="mytable")
|
|
423
|
-
assert identifier == "myschema.mytable"
|
|
428
|
+
assert identifier == f"{db}.myschema.mytable"
|
|
@@ -131,7 +131,13 @@ class TestTpchMetadata:
|
|
|
131
131
|
"""get_tables() should return TPC-H tables."""
|
|
132
132
|
tables = tpch_setup.get_tables(schema_name="public")
|
|
133
133
|
tpch_tables = {t for t in tables if t.startswith("tpch_")}
|
|
134
|
-
expected = {
|
|
134
|
+
expected = {
|
|
135
|
+
"tpch_region",
|
|
136
|
+
"tpch_nation",
|
|
137
|
+
"tpch_supplier",
|
|
138
|
+
"tpch_customer",
|
|
139
|
+
"tpch_orders",
|
|
140
|
+
}
|
|
135
141
|
assert expected.issubset(tpch_tables)
|
|
136
142
|
|
|
137
143
|
def test_get_schema_columns(self, tpch_setup):
|
|
@@ -3,9 +3,10 @@
|
|
|
3
3
|
# See http://www.apache.org/licenses/LICENSE-2.0 for details.
|
|
4
4
|
|
|
5
5
|
import pytest
|
|
6
|
-
from datus_postgresql import PostgreSQLConfig
|
|
7
6
|
from pydantic import ValidationError
|
|
8
7
|
|
|
8
|
+
from datus_postgresql import PostgreSQLConfig
|
|
9
|
+
|
|
9
10
|
|
|
10
11
|
@pytest.mark.acceptance
|
|
11
12
|
def test_config_with_all_required_fields():
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
from unittest.mock import patch
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
|
+
|
|
8
9
|
from datus_db_core import DatusDbException
|
|
9
10
|
from datus_postgresql import PostgreSQLConfig, PostgreSQLConnector
|
|
10
11
|
|
|
@@ -223,10 +224,11 @@ def test_full_name_with_schema():
|
|
|
223
224
|
|
|
224
225
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
225
226
|
connector = PostgreSQLConnector(config)
|
|
227
|
+
connector.database_name = "postgres"
|
|
226
228
|
connector.schema_name = "public"
|
|
227
229
|
full_name = connector.full_name(schema_name="myschema", table_name="mytable")
|
|
228
230
|
|
|
229
|
-
assert full_name == '"myschema"."mytable"'
|
|
231
|
+
assert full_name == '"postgres"."myschema"."mytable"'
|
|
230
232
|
|
|
231
233
|
|
|
232
234
|
def test_full_name_with_default_schema():
|
|
@@ -235,10 +237,11 @@ def test_full_name_with_default_schema():
|
|
|
235
237
|
|
|
236
238
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
237
239
|
connector = PostgreSQLConnector(config)
|
|
240
|
+
connector.database_name = "postgres"
|
|
238
241
|
connector.schema_name = "public"
|
|
239
242
|
full_name = connector.full_name(table_name="mytable")
|
|
240
243
|
|
|
241
|
-
assert full_name == '"public"."mytable"'
|
|
244
|
+
assert full_name == '"postgres"."public"."mytable"'
|
|
242
245
|
|
|
243
246
|
|
|
244
247
|
def test_full_name_with_special_characters():
|
|
@@ -247,10 +250,11 @@ def test_full_name_with_special_characters():
|
|
|
247
250
|
|
|
248
251
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
249
252
|
connector = PostgreSQLConnector(config)
|
|
253
|
+
connector.database_name = "postgres"
|
|
250
254
|
connector.schema_name = "public"
|
|
251
255
|
full_name = connector.full_name(schema_name='my"schema', table_name='my"table')
|
|
252
256
|
|
|
253
|
-
assert full_name == '"my""schema"."my""table"'
|
|
257
|
+
assert full_name == '"postgres"."my""schema"."my""table"'
|
|
254
258
|
|
|
255
259
|
|
|
256
260
|
def test_identifier_with_schema():
|
|
@@ -259,10 +263,11 @@ def test_identifier_with_schema():
|
|
|
259
263
|
|
|
260
264
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
261
265
|
connector = PostgreSQLConnector(config)
|
|
266
|
+
connector.database_name = "postgres"
|
|
262
267
|
connector.schema_name = "public"
|
|
263
268
|
identifier = connector.identifier(schema_name="myschema", table_name="mytable")
|
|
264
269
|
|
|
265
|
-
assert identifier == "myschema.mytable"
|
|
270
|
+
assert identifier == "postgres.myschema.mytable"
|
|
266
271
|
|
|
267
272
|
|
|
268
273
|
def test_identifier_with_default_schema():
|
|
@@ -271,10 +276,11 @@ def test_identifier_with_default_schema():
|
|
|
271
276
|
|
|
272
277
|
with patch("datus_sqlalchemy.SQLAlchemyConnector.__init__", return_value=None):
|
|
273
278
|
connector = PostgreSQLConnector(config)
|
|
279
|
+
connector.database_name = "postgres"
|
|
274
280
|
connector.schema_name = "public"
|
|
275
281
|
identifier = connector.identifier(table_name="mytable")
|
|
276
282
|
|
|
277
|
-
assert identifier == "public.mytable"
|
|
283
|
+
assert identifier == "postgres.public.mytable"
|
|
278
284
|
|
|
279
285
|
|
|
280
286
|
@pytest.mark.acceptance
|
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
# Byte-compiled / optimized / DLL files
|
|
2
|
-
__pycache__/
|
|
3
|
-
*.py[cod]
|
|
4
|
-
*$py.class
|
|
5
|
-
|
|
6
|
-
# C extensions
|
|
7
|
-
*.so
|
|
8
|
-
|
|
9
|
-
# Distribution / packaging
|
|
10
|
-
.Python
|
|
11
|
-
build/
|
|
12
|
-
develop-eggs/
|
|
13
|
-
dist/
|
|
14
|
-
downloads/
|
|
15
|
-
eggs/
|
|
16
|
-
.eggs/
|
|
17
|
-
lib/
|
|
18
|
-
lib64/
|
|
19
|
-
parts/
|
|
20
|
-
sdist/
|
|
21
|
-
var/
|
|
22
|
-
wheels/
|
|
23
|
-
pip-wheel-metadata/
|
|
24
|
-
share/python-wheels/
|
|
25
|
-
*.egg-info/
|
|
26
|
-
.installed.cfg
|
|
27
|
-
*.egg
|
|
28
|
-
MANIFEST
|
|
29
|
-
|
|
30
|
-
# PyInstaller
|
|
31
|
-
*.manifest
|
|
32
|
-
*.spec
|
|
33
|
-
|
|
34
|
-
# Installer logs
|
|
35
|
-
pip-log.txt
|
|
36
|
-
pip-delete-this-directory.txt
|
|
37
|
-
|
|
38
|
-
# Unit test / coverage reports
|
|
39
|
-
htmlcov/
|
|
40
|
-
.tox/
|
|
41
|
-
.nox/
|
|
42
|
-
.coverage
|
|
43
|
-
.coverage.*
|
|
44
|
-
.cache
|
|
45
|
-
nosetests.xml
|
|
46
|
-
coverage.xml
|
|
47
|
-
*.cover
|
|
48
|
-
*.py,cover
|
|
49
|
-
.hypothesis/
|
|
50
|
-
.pytest_cache/
|
|
51
|
-
|
|
52
|
-
# Translations
|
|
53
|
-
*.mo
|
|
54
|
-
*.pot
|
|
55
|
-
|
|
56
|
-
# Django stuff:
|
|
57
|
-
*.log
|
|
58
|
-
local_settings.py
|
|
59
|
-
db.sqlite3
|
|
60
|
-
db.sqlite3-journal
|
|
61
|
-
|
|
62
|
-
# Flask stuff:
|
|
63
|
-
instance/
|
|
64
|
-
.webassets-cache
|
|
65
|
-
|
|
66
|
-
# Scrapy stuff:
|
|
67
|
-
.scrapy
|
|
68
|
-
|
|
69
|
-
# Sphinx documentation
|
|
70
|
-
docs/_build/
|
|
71
|
-
|
|
72
|
-
# PyBuilder
|
|
73
|
-
target/
|
|
74
|
-
|
|
75
|
-
# Jupyter Notebook
|
|
76
|
-
.ipynb_checkpoints
|
|
77
|
-
|
|
78
|
-
# IPython
|
|
79
|
-
profile_default/
|
|
80
|
-
ipython_config.py
|
|
81
|
-
|
|
82
|
-
# pyenv
|
|
83
|
-
.python-version
|
|
84
|
-
|
|
85
|
-
# pipenv
|
|
86
|
-
Pipfile.lock
|
|
87
|
-
|
|
88
|
-
# uv
|
|
89
|
-
uv.lock
|
|
90
|
-
|
|
91
|
-
# PEP 582
|
|
92
|
-
__pypackages__/
|
|
93
|
-
|
|
94
|
-
# Celery stuff
|
|
95
|
-
celerybeat-schedule
|
|
96
|
-
celerybeat.pid
|
|
97
|
-
|
|
98
|
-
# SageMath parsed files
|
|
99
|
-
*.sage.py
|
|
100
|
-
|
|
101
|
-
# Environments
|
|
102
|
-
.env
|
|
103
|
-
.venv
|
|
104
|
-
env/
|
|
105
|
-
venv/
|
|
106
|
-
ENV/
|
|
107
|
-
env.bak/
|
|
108
|
-
venv.bak/
|
|
109
|
-
|
|
110
|
-
# Spyder project settings
|
|
111
|
-
.spyderproject
|
|
112
|
-
.spyproject
|
|
113
|
-
|
|
114
|
-
# Rope project settings
|
|
115
|
-
.ropeproject
|
|
116
|
-
|
|
117
|
-
# mkdocs documentation
|
|
118
|
-
/site
|
|
119
|
-
|
|
120
|
-
# mypy
|
|
121
|
-
.mypy_cache/
|
|
122
|
-
.dmypy.json
|
|
123
|
-
dmypy.json
|
|
124
|
-
|
|
125
|
-
# Pyre type checker
|
|
126
|
-
.pyre/
|
|
127
|
-
|
|
128
|
-
# IDEs
|
|
129
|
-
.vscode/
|
|
130
|
-
.idea/
|
|
131
|
-
*.swp
|
|
132
|
-
*.swo
|
|
133
|
-
*~
|
|
134
|
-
|
|
135
|
-
# OS
|
|
136
|
-
.DS_Store
|
|
137
|
-
Thumbs.db
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
.omc
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|