meerschaum 2.8.3__py3-none-any.whl → 2.9.0__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.
- meerschaum/_internal/arguments/_parser.py +5 -0
- meerschaum/actions/drop.py +1 -1
- meerschaum/actions/start.py +14 -6
- meerschaum/actions/sync.py +9 -0
- meerschaum/api/__init__.py +9 -3
- meerschaum/api/_chunks.py +67 -0
- meerschaum/api/dash/callbacks/__init__.py +5 -2
- meerschaum/api/dash/callbacks/custom.py +21 -8
- meerschaum/api/dash/callbacks/dashboard.py +26 -4
- meerschaum/api/dash/callbacks/settings/__init__.py +8 -0
- meerschaum/api/dash/callbacks/settings/password_reset.py +76 -0
- meerschaum/api/dash/components.py +136 -25
- meerschaum/api/dash/pages/__init__.py +1 -0
- meerschaum/api/dash/pages/dashboard.py +11 -9
- meerschaum/api/dash/pages/plugins.py +31 -27
- meerschaum/api/dash/pages/settings/__init__.py +8 -0
- meerschaum/api/dash/pages/settings/password_reset.py +63 -0
- meerschaum/api/dash/webterm.py +6 -3
- meerschaum/api/resources/static/css/dash.css +8 -1
- meerschaum/api/resources/templates/termpage.html +4 -0
- meerschaum/api/routes/_pipes.py +234 -82
- meerschaum/config/_default.py +4 -0
- meerschaum/config/_version.py +1 -1
- meerschaum/connectors/__init__.py +1 -0
- meerschaum/connectors/api/_APIConnector.py +12 -1
- meerschaum/connectors/api/_pipes.py +106 -45
- meerschaum/connectors/api/_plugins.py +51 -45
- meerschaum/connectors/api/_request.py +1 -1
- meerschaum/connectors/parse.py +1 -2
- meerschaum/connectors/sql/_SQLConnector.py +4 -1
- meerschaum/connectors/sql/_cli.py +1 -0
- meerschaum/connectors/sql/_create_engine.py +51 -4
- meerschaum/connectors/sql/_pipes.py +38 -6
- meerschaum/connectors/sql/_sql.py +35 -4
- meerschaum/connectors/valkey/_ValkeyConnector.py +2 -0
- meerschaum/connectors/valkey/_pipes.py +51 -39
- meerschaum/core/Pipe/__init__.py +1 -0
- meerschaum/core/Pipe/_data.py +1 -2
- meerschaum/core/Pipe/_sync.py +64 -4
- meerschaum/core/Pipe/_verify.py +23 -8
- meerschaum/jobs/systemd.py +1 -1
- meerschaum/plugins/_Plugin.py +21 -5
- meerschaum/plugins/__init__.py +32 -8
- meerschaum/utils/dataframe.py +139 -2
- meerschaum/utils/dtypes/__init__.py +211 -1
- meerschaum/utils/dtypes/sql.py +296 -5
- meerschaum/utils/formatting/_shell.py +1 -4
- meerschaum/utils/misc.py +1 -1
- meerschaum/utils/packages/_packages.py +8 -2
- meerschaum/utils/process.py +27 -3
- meerschaum/utils/schedule.py +3 -3
- meerschaum/utils/sql.py +140 -12
- meerschaum/utils/venv/__init__.py +10 -2
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/METADATA +17 -3
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/RECORD +61 -61
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/WHEEL +1 -1
- meerschaum/_internal/gui/__init__.py +0 -43
- meerschaum/_internal/gui/app/__init__.py +0 -50
- meerschaum/_internal/gui/app/_windows.py +0 -74
- meerschaum/_internal/gui/app/actions.py +0 -30
- meerschaum/_internal/gui/app/pipes.py +0 -47
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/LICENSE +0 -0
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/NOTICE +0 -0
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/entry_points.txt +0 -0
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/top_level.txt +0 -0
- {meerschaum-2.8.3.dist-info → meerschaum-2.9.0.dist-info}/zip-safe +0 -0
meerschaum/utils/schedule.py
CHANGED
@@ -95,7 +95,7 @@ def schedule_function(
|
|
95
95
|
A `SuccessTuple` upon exit.
|
96
96
|
"""
|
97
97
|
import asyncio
|
98
|
-
from meerschaum.utils.misc import filter_keywords
|
98
|
+
from meerschaum.utils.misc import filter_keywords
|
99
99
|
|
100
100
|
global _scheduler
|
101
101
|
kw['debug'] = debug
|
@@ -103,7 +103,7 @@ def schedule_function(
|
|
103
103
|
|
104
104
|
_ = mrsm.attempt_import('attrs', lazy=False)
|
105
105
|
apscheduler = mrsm.attempt_import('apscheduler', lazy=False)
|
106
|
-
now =
|
106
|
+
now = datetime.now(timezone.utc)
|
107
107
|
trigger = parse_schedule(schedule, now=now)
|
108
108
|
_scheduler = apscheduler.AsyncScheduler(identity='mrsm-scheduler')
|
109
109
|
try:
|
@@ -296,7 +296,7 @@ def parse_start_time(schedule: str, now: Optional[datetime] = None) -> datetime:
|
|
296
296
|
dateutil_parser = mrsm.attempt_import('dateutil.parser')
|
297
297
|
starting_parts = schedule.split(STARTING_KEYWORD)
|
298
298
|
starting_str = ('now' if len(starting_parts) == 1 else starting_parts[-1]).strip()
|
299
|
-
now = now or
|
299
|
+
now = now or datetime.now(timezone.utc)
|
300
300
|
try:
|
301
301
|
if starting_str == 'now':
|
302
302
|
starting_ts = now
|
meerschaum/utils/sql.py
CHANGED
@@ -41,13 +41,13 @@ version_queries = {
|
|
41
41
|
}
|
42
42
|
SKIP_IF_EXISTS_FLAVORS = {'mssql', 'oracle'}
|
43
43
|
DROP_IF_EXISTS_FLAVORS = {
|
44
|
-
'timescaledb', 'postgresql', 'citus', 'mssql', 'mysql', 'mariadb', 'sqlite',
|
44
|
+
'timescaledb', 'postgresql', 'postgis', 'citus', 'mssql', 'mysql', 'mariadb', 'sqlite',
|
45
45
|
}
|
46
46
|
DROP_INDEX_IF_EXISTS_FLAVORS = {
|
47
|
-
'mssql', 'timescaledb', 'postgresql', 'sqlite', 'citus',
|
47
|
+
'mssql', 'timescaledb', 'postgresql', 'postgis', 'sqlite', 'citus',
|
48
48
|
}
|
49
49
|
SKIP_AUTO_INCREMENT_FLAVORS = {'citus', 'duckdb'}
|
50
|
-
COALESCE_UNIQUE_INDEX_FLAVORS = {'timescaledb', 'postgresql', 'citus'}
|
50
|
+
COALESCE_UNIQUE_INDEX_FLAVORS = {'timescaledb', 'postgresql', 'postgis', 'citus'}
|
51
51
|
UPDATE_QUERIES = {
|
52
52
|
'default': """
|
53
53
|
UPDATE {target_table_name} AS f
|
@@ -73,6 +73,12 @@ UPDATE_QUERIES = {
|
|
73
73
|
FROM {patch_table_name}
|
74
74
|
ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
|
75
75
|
""",
|
76
|
+
'postgis-upsert': """
|
77
|
+
INSERT INTO {target_table_name} ({patch_cols_str})
|
78
|
+
SELECT {patch_cols_str}
|
79
|
+
FROM {patch_table_name}
|
80
|
+
ON CONFLICT ({join_cols_str}) DO {update_or_nothing} {sets_subquery_none_excluded}
|
81
|
+
""",
|
76
82
|
'citus-upsert': """
|
77
83
|
INSERT INTO {target_table_name} ({patch_cols_str})
|
78
84
|
SELECT {patch_cols_str}
|
@@ -482,6 +488,7 @@ table_wrappers = {
|
|
482
488
|
'citus' : ('"', '"'),
|
483
489
|
'duckdb' : ('"', '"'),
|
484
490
|
'postgresql' : ('"', '"'),
|
491
|
+
'postgis' : ('"', '"'),
|
485
492
|
'sqlite' : ('"', '"'),
|
486
493
|
'mysql' : ('`', '`'),
|
487
494
|
'mariadb' : ('`', '`'),
|
@@ -494,6 +501,7 @@ max_name_lens = {
|
|
494
501
|
'mssql' : 128,
|
495
502
|
'oracle' : 30,
|
496
503
|
'postgresql' : 64,
|
504
|
+
'postgis' : 64,
|
497
505
|
'timescaledb': 64,
|
498
506
|
'citus' : 64,
|
499
507
|
'cockroachdb': 64,
|
@@ -501,10 +509,11 @@ max_name_lens = {
|
|
501
509
|
'mysql' : 64,
|
502
510
|
'mariadb' : 64,
|
503
511
|
}
|
504
|
-
json_flavors = {'postgresql', 'timescaledb', 'citus', 'cockroachdb'}
|
512
|
+
json_flavors = {'postgresql', 'postgis', 'timescaledb', 'citus', 'cockroachdb'}
|
505
513
|
NO_SCHEMA_FLAVORS = {'oracle', 'sqlite', 'mysql', 'mariadb', 'duckdb'}
|
506
514
|
DEFAULT_SCHEMA_FLAVORS = {
|
507
515
|
'postgresql': 'public',
|
516
|
+
'postgis': 'public',
|
508
517
|
'timescaledb': 'public',
|
509
518
|
'citus': 'public',
|
510
519
|
'cockroachdb': 'public',
|
@@ -519,7 +528,7 @@ NO_CTE_FLAVORS = {'mysql', 'mariadb'}
|
|
519
528
|
NO_SELECT_INTO_FLAVORS = {'sqlite', 'oracle', 'mysql', 'mariadb', 'duckdb'}
|
520
529
|
|
521
530
|
|
522
|
-
def clean(substring: str) ->
|
531
|
+
def clean(substring: str) -> None:
|
523
532
|
"""
|
524
533
|
Ensure a substring is clean enough to be inserted into a SQL query.
|
525
534
|
Raises an exception when banned words are used.
|
@@ -549,6 +558,7 @@ def dateadd_str(
|
|
549
558
|
Currently supported flavors:
|
550
559
|
|
551
560
|
- `'postgresql'`
|
561
|
+
- `'postgis'`
|
552
562
|
- `'timescaledb'`
|
553
563
|
- `'citus'`
|
554
564
|
- `'cockroachdb'`
|
@@ -653,7 +663,7 @@ def dateadd_str(
|
|
653
663
|
)
|
654
664
|
|
655
665
|
da = ""
|
656
|
-
if flavor in ('postgresql', 'timescaledb', 'cockroachdb', 'citus'):
|
666
|
+
if flavor in ('postgresql', 'postgis', 'timescaledb', 'cockroachdb', 'citus'):
|
657
667
|
begin = (
|
658
668
|
f"CAST({begin} AS {db_type})" if begin != 'now'
|
659
669
|
else f"CAST(NOW() AT TIME ZONE 'utc' AS {db_type})"
|
@@ -922,6 +932,7 @@ def build_where(
|
|
922
932
|
params: Dict[str, Any],
|
923
933
|
connector: Optional[mrsm.connectors.sql.SQLConnector] = None,
|
924
934
|
with_where: bool = True,
|
935
|
+
flavor: str = 'postgresql',
|
925
936
|
) -> str:
|
926
937
|
"""
|
927
938
|
Build the `WHERE` clause based on the input criteria.
|
@@ -941,6 +952,9 @@ def build_where(
|
|
941
952
|
with_where: bool, default True:
|
942
953
|
If `True`, include the leading `'WHERE'` string.
|
943
954
|
|
955
|
+
flavor: str, default 'postgresql'
|
956
|
+
If `connector` is `None`, fall back to this flavor.
|
957
|
+
|
944
958
|
Returns
|
945
959
|
-------
|
946
960
|
A `str` of the `WHERE` clause from the input `params` dictionary for the connector's flavor.
|
@@ -969,13 +983,11 @@ def build_where(
|
|
969
983
|
warn(f"Aborting build_where() due to possible SQL injection.")
|
970
984
|
return ''
|
971
985
|
|
972
|
-
if connector is None
|
973
|
-
from meerschaum import get_connector
|
974
|
-
connector = get_connector('sql')
|
986
|
+
query_flavor = getattr(connector, 'flavor', flavor) if connector is not None else flavor
|
975
987
|
where = ""
|
976
988
|
leading_and = "\n AND "
|
977
989
|
for key, value in params.items():
|
978
|
-
_key = sql_item_name(key,
|
990
|
+
_key = sql_item_name(key, query_flavor, None)
|
979
991
|
### search across a list (i.e. IN syntax)
|
980
992
|
if isinstance(value, Iterable) and not isinstance(value, (dict, str)):
|
981
993
|
includes = [
|
@@ -1286,7 +1298,24 @@ def get_table_cols_types(
|
|
1286
1298
|
if cols_types_docs and not cols_types_docs_filtered:
|
1287
1299
|
cols_types_docs_filtered = cols_types_docs
|
1288
1300
|
|
1289
|
-
|
1301
|
+
### NOTE: Check for PostGIS GEOMETRY columns.
|
1302
|
+
geometry_cols_types = {}
|
1303
|
+
user_defined_cols = [
|
1304
|
+
doc
|
1305
|
+
for doc in cols_types_docs_filtered
|
1306
|
+
if str(doc.get('type', None)).upper() == 'USER-DEFINED'
|
1307
|
+
]
|
1308
|
+
if user_defined_cols:
|
1309
|
+
geometry_cols_types.update(
|
1310
|
+
get_postgis_geo_columns_types(
|
1311
|
+
connectable,
|
1312
|
+
table,
|
1313
|
+
schema=schema,
|
1314
|
+
debug=debug,
|
1315
|
+
)
|
1316
|
+
)
|
1317
|
+
|
1318
|
+
cols_types = {
|
1290
1319
|
(
|
1291
1320
|
doc['column']
|
1292
1321
|
if flavor != 'oracle' else (
|
@@ -1307,6 +1336,8 @@ def get_table_cols_types(
|
|
1307
1336
|
)
|
1308
1337
|
for doc in cols_types_docs_filtered
|
1309
1338
|
}
|
1339
|
+
cols_types.update(geometry_cols_types)
|
1340
|
+
return cols_types
|
1310
1341
|
except Exception as e:
|
1311
1342
|
warn(f"Failed to fetch columns for table '{table}':\n{e}")
|
1312
1343
|
return {}
|
@@ -1548,7 +1579,7 @@ def get_update_queries(
|
|
1548
1579
|
from meerschaum.utils.debug import dprint
|
1549
1580
|
from meerschaum.utils.dtypes import are_dtypes_equal
|
1550
1581
|
from meerschaum.utils.dtypes.sql import DB_FLAVORS_CAST_DTYPES, get_pd_type_from_db_type
|
1551
|
-
flavor = flavor or (connectable
|
1582
|
+
flavor = flavor or getattr(connectable, 'flavor', None)
|
1552
1583
|
if not flavor:
|
1553
1584
|
raise ValueError("Provide a flavor if using a SQLAlchemy session.")
|
1554
1585
|
if (
|
@@ -1809,6 +1840,8 @@ def get_null_replacement(typ: str, flavor: str) -> str:
|
|
1809
1840
|
"""
|
1810
1841
|
from meerschaum.utils.dtypes import are_dtypes_equal
|
1811
1842
|
from meerschaum.utils.dtypes.sql import DB_FLAVORS_CAST_DTYPES
|
1843
|
+
if 'geometry' in typ.lower():
|
1844
|
+
return '010100000000008058346FCDC100008058346FCDC1'
|
1812
1845
|
if 'int' in typ.lower() or typ.lower() in ('numeric', 'number'):
|
1813
1846
|
return '-987654321'
|
1814
1847
|
if 'bool' in typ.lower() or typ.lower() == 'bit':
|
@@ -2493,3 +2526,98 @@ def get_reset_autoincrement_queries(
|
|
2493
2526
|
)
|
2494
2527
|
for query in reset_queries
|
2495
2528
|
]
|
2529
|
+
|
2530
|
+
|
2531
|
+
def get_postgis_geo_columns_types(
|
2532
|
+
connectable: Union[
|
2533
|
+
'mrsm.connectors.sql.SQLConnector',
|
2534
|
+
'sqlalchemy.orm.session.Session',
|
2535
|
+
'sqlalchemy.engine.base.Engine'
|
2536
|
+
],
|
2537
|
+
table: str,
|
2538
|
+
schema: Optional[str] = 'public',
|
2539
|
+
debug: bool = False,
|
2540
|
+
) -> Dict[str, str]:
|
2541
|
+
"""
|
2542
|
+
Return the
|
2543
|
+
"""
|
2544
|
+
from meerschaum.utils.dtypes import get_geometry_type_srid
|
2545
|
+
default_type, default_srid = get_geometry_type_srid()
|
2546
|
+
default_type = default_type.upper()
|
2547
|
+
|
2548
|
+
clean(table)
|
2549
|
+
clean(str(schema))
|
2550
|
+
schema = schema or 'public'
|
2551
|
+
truncated_schema_name = truncate_item_name(schema, flavor='postgis')
|
2552
|
+
truncated_table_name = truncate_item_name(table, flavor='postgis')
|
2553
|
+
query = (
|
2554
|
+
"SELECT \"f_geometry_column\" AS \"column\", 'GEOMETRY' AS \"func\", \"type\", \"srid\"\n"
|
2555
|
+
"FROM \"geometry_columns\"\n"
|
2556
|
+
f"WHERE \"f_table_schema\" = '{truncated_schema_name}'\n"
|
2557
|
+
f" AND \"f_table_name\" = '{truncated_table_name}'\n"
|
2558
|
+
"UNION ALL\n"
|
2559
|
+
"SELECT \"f_geography_column\" AS \"column\", 'GEOGRAPHY' AS \"func\", \"type\", \"srid\"\n"
|
2560
|
+
"FROM \"geography_columns\"\n"
|
2561
|
+
f"WHERE \"f_table_schema\" = '{truncated_schema_name}'\n"
|
2562
|
+
f" AND \"f_table_name\" = '{truncated_table_name}'\n"
|
2563
|
+
)
|
2564
|
+
debug_kwargs = {'debug': debug} if isinstance(connectable, mrsm.connectors.SQLConnector) else {}
|
2565
|
+
result_rows = [
|
2566
|
+
row
|
2567
|
+
for row in connectable.execute(query, **debug_kwargs).fetchall()
|
2568
|
+
]
|
2569
|
+
cols_type_tuples = {
|
2570
|
+
row[0]: (row[1], row[2], row[3])
|
2571
|
+
for row in result_rows
|
2572
|
+
}
|
2573
|
+
|
2574
|
+
geometry_cols_types = {
|
2575
|
+
col: (
|
2576
|
+
f"{func}({typ.upper()}, {srid})"
|
2577
|
+
if srid
|
2578
|
+
else (
|
2579
|
+
func
|
2580
|
+
+ (
|
2581
|
+
f'({typ.upper()})'
|
2582
|
+
if typ.upper() not in ('GEOMETRY', 'GEOGRAPHY')
|
2583
|
+
else ''
|
2584
|
+
)
|
2585
|
+
)
|
2586
|
+
)
|
2587
|
+
for col, (func, typ, srid) in cols_type_tuples.items()
|
2588
|
+
}
|
2589
|
+
return geometry_cols_types
|
2590
|
+
|
2591
|
+
|
2592
|
+
def get_create_schema_if_not_exists_queries(
|
2593
|
+
schema: str,
|
2594
|
+
flavor: str,
|
2595
|
+
) -> List[str]:
|
2596
|
+
"""
|
2597
|
+
Return the queries to create a schema if it does not yet exist.
|
2598
|
+
For databases which do not support schemas, an empty list will be returned.
|
2599
|
+
"""
|
2600
|
+
if not schema:
|
2601
|
+
return []
|
2602
|
+
|
2603
|
+
if flavor in NO_SCHEMA_FLAVORS:
|
2604
|
+
return []
|
2605
|
+
|
2606
|
+
clean(schema)
|
2607
|
+
|
2608
|
+
if flavor == 'mssql':
|
2609
|
+
return [
|
2610
|
+
(
|
2611
|
+
f"IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = '{schema}')\n"
|
2612
|
+
"BEGIN\n"
|
2613
|
+
f" EXEC('CREATE SCHEMA {sql_item_name(schema, flavor)}');\n"
|
2614
|
+
"END;"
|
2615
|
+
)
|
2616
|
+
]
|
2617
|
+
|
2618
|
+
if flavor == 'oracle':
|
2619
|
+
return []
|
2620
|
+
|
2621
|
+
return [
|
2622
|
+
f"CREATE SCHEMA IF NOT EXISTS {sql_item_name(schema, flavor)};"
|
2623
|
+
]
|
@@ -86,7 +86,10 @@ def activate_venv(
|
|
86
86
|
target = target_path.as_posix()
|
87
87
|
|
88
88
|
if venv in active_venvs_order:
|
89
|
-
|
89
|
+
try:
|
90
|
+
sys.path.remove(target)
|
91
|
+
except Exception:
|
92
|
+
pass
|
90
93
|
try:
|
91
94
|
active_venvs_order.remove(venv)
|
92
95
|
except Exception:
|
@@ -410,6 +413,8 @@ def init_venv(
|
|
410
413
|
pass
|
411
414
|
|
412
415
|
def wait_for_lock():
|
416
|
+
if platform.system() == 'Windows':
|
417
|
+
return
|
413
418
|
max_lock_seconds = 30.0
|
414
419
|
sleep_message_seconds = 5.0
|
415
420
|
step_sleep_seconds = 0.1
|
@@ -595,7 +600,7 @@ def venv_exec(
|
|
595
600
|
as_proc: bool = False,
|
596
601
|
capture_output: bool = True,
|
597
602
|
debug: bool = False,
|
598
|
-
) -> Union[bool, Tuple[int, bytes, bytes]]:
|
603
|
+
) -> Union[bool, Tuple[int, bytes, bytes], 'subprocess.Popen']:
|
599
604
|
"""
|
600
605
|
Execute Python code in a subprocess via a virtual environment's interpeter.
|
601
606
|
Return `True` if the code successfully executes, `False` on failure.
|
@@ -630,6 +635,8 @@ def venv_exec(
|
|
630
635
|
import subprocess
|
631
636
|
import platform
|
632
637
|
from meerschaum.utils.debug import dprint
|
638
|
+
from meerschaum.utils.process import _child_processes
|
639
|
+
|
633
640
|
executable = venv_executable(venv=venv)
|
634
641
|
cmd_list = [executable, '-c', code]
|
635
642
|
if env is None:
|
@@ -656,6 +663,7 @@ def venv_exec(
|
|
656
663
|
**group_kwargs
|
657
664
|
)
|
658
665
|
if as_proc:
|
666
|
+
_child_processes.append(process)
|
659
667
|
return process
|
660
668
|
stdout, stderr = process.communicate()
|
661
669
|
exit_code = process.returncode
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.2
|
2
2
|
Name: meerschaum
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.9.0
|
4
4
|
Summary: Sync Time-Series Pipes with Meerschaum
|
5
5
|
Home-page: https://meerschaum.io
|
6
6
|
Author: Bennett Meares
|
@@ -87,6 +87,10 @@ Requires-Dist: mycli>=1.23.2; extra == "cli"
|
|
87
87
|
Requires-Dist: litecli>=1.5.0; extra == "cli"
|
88
88
|
Requires-Dist: mssql-cli>=1.0.0; extra == "cli"
|
89
89
|
Requires-Dist: gadwall>=0.2.0; extra == "cli"
|
90
|
+
Provides-Extra: gis
|
91
|
+
Requires-Dist: pyproj>=3.7.1; extra == "gis"
|
92
|
+
Requires-Dist: geopandas>=1.0.1; extra == "gis"
|
93
|
+
Requires-Dist: shapely>=2.0.7; extra == "gis"
|
90
94
|
Provides-Extra: stack
|
91
95
|
Requires-Dist: docker-compose>=1.29.2; extra == "stack"
|
92
96
|
Provides-Extra: build
|
@@ -114,7 +118,6 @@ Requires-Dist: mkdocs-linkcheck>=1.0.6; extra == "docs"
|
|
114
118
|
Requires-Dist: mkdocs-redirects>=1.0.4; extra == "docs"
|
115
119
|
Requires-Dist: jinja2==3.0.3; extra == "docs"
|
116
120
|
Provides-Extra: gui
|
117
|
-
Requires-Dist: toga>=0.3.0-dev29; extra == "gui"
|
118
121
|
Requires-Dist: pywebview>=3.6.3; extra == "gui"
|
119
122
|
Requires-Dist: pycparser>=2.21.0; extra == "gui"
|
120
123
|
Provides-Extra: extras
|
@@ -132,6 +135,7 @@ Requires-Dist: partd>=1.4.2; extra == "sql"
|
|
132
135
|
Requires-Dist: pytz; extra == "sql"
|
133
136
|
Requires-Dist: joblib>=0.17.0; extra == "sql"
|
134
137
|
Requires-Dist: SQLAlchemy>=2.0.5; extra == "sql"
|
138
|
+
Requires-Dist: GeoAlchemy2>=0.17.1; extra == "sql"
|
135
139
|
Requires-Dist: databases>=0.4.0; extra == "sql"
|
136
140
|
Requires-Dist: aiosqlite>=0.16.0; extra == "sql"
|
137
141
|
Requires-Dist: asyncpg>=0.21.0; extra == "sql"
|
@@ -164,6 +168,9 @@ Requires-Dist: fasteners>=0.19.0; extra == "sql"
|
|
164
168
|
Requires-Dist: virtualenv>=20.1.0; extra == "sql"
|
165
169
|
Requires-Dist: attrs>=24.2.0; extra == "sql"
|
166
170
|
Requires-Dist: uv>=0.2.11; extra == "sql"
|
171
|
+
Requires-Dist: pyproj>=3.7.1; extra == "sql"
|
172
|
+
Requires-Dist: geopandas>=1.0.1; extra == "sql"
|
173
|
+
Requires-Dist: shapely>=2.0.7; extra == "sql"
|
167
174
|
Provides-Extra: dash
|
168
175
|
Requires-Dist: Flask-Compress>=1.10.1; extra == "dash"
|
169
176
|
Requires-Dist: dash>=2.6.2; extra == "dash"
|
@@ -192,6 +199,7 @@ Requires-Dist: partd>=1.4.2; extra == "api"
|
|
192
199
|
Requires-Dist: pytz; extra == "api"
|
193
200
|
Requires-Dist: joblib>=0.17.0; extra == "api"
|
194
201
|
Requires-Dist: SQLAlchemy>=2.0.5; extra == "api"
|
202
|
+
Requires-Dist: GeoAlchemy2>=0.17.1; extra == "api"
|
195
203
|
Requires-Dist: databases>=0.4.0; extra == "api"
|
196
204
|
Requires-Dist: aiosqlite>=0.16.0; extra == "api"
|
197
205
|
Requires-Dist: asyncpg>=0.21.0; extra == "api"
|
@@ -224,6 +232,9 @@ Requires-Dist: fasteners>=0.19.0; extra == "api"
|
|
224
232
|
Requires-Dist: virtualenv>=20.1.0; extra == "api"
|
225
233
|
Requires-Dist: attrs>=24.2.0; extra == "api"
|
226
234
|
Requires-Dist: uv>=0.2.11; extra == "api"
|
235
|
+
Requires-Dist: pyproj>=3.7.1; extra == "api"
|
236
|
+
Requires-Dist: geopandas>=1.0.1; extra == "api"
|
237
|
+
Requires-Dist: shapely>=2.0.7; extra == "api"
|
227
238
|
Requires-Dist: pprintpp>=0.4.0; extra == "api"
|
228
239
|
Requires-Dist: asciitree>=0.3.3; extra == "api"
|
229
240
|
Requires-Dist: typing-extensions>=4.7.1; extra == "api"
|
@@ -286,7 +297,9 @@ Requires-Dist: aiomysql>=0.0.21; extra == "full"
|
|
286
297
|
Requires-Dist: sqlalchemy-cockroachdb>=2.0.0; extra == "full"
|
287
298
|
Requires-Dist: duckdb>=1.0.0; extra == "full"
|
288
299
|
Requires-Dist: duckdb-engine>=0.13.0; extra == "full"
|
289
|
-
Requires-Dist:
|
300
|
+
Requires-Dist: pyproj>=3.7.1; extra == "full"
|
301
|
+
Requires-Dist: geopandas>=1.0.1; extra == "full"
|
302
|
+
Requires-Dist: shapely>=2.0.7; extra == "full"
|
290
303
|
Requires-Dist: pywebview>=3.6.3; extra == "full"
|
291
304
|
Requires-Dist: pycparser>=2.21.0; extra == "full"
|
292
305
|
Requires-Dist: numpy>=1.18.5; extra == "full"
|
@@ -297,6 +310,7 @@ Requires-Dist: partd>=1.4.2; extra == "full"
|
|
297
310
|
Requires-Dist: pytz; extra == "full"
|
298
311
|
Requires-Dist: joblib>=0.17.0; extra == "full"
|
299
312
|
Requires-Dist: SQLAlchemy>=2.0.5; extra == "full"
|
313
|
+
Requires-Dist: GeoAlchemy2>=0.17.1; extra == "full"
|
300
314
|
Requires-Dist: databases>=0.4.0; extra == "full"
|
301
315
|
Requires-Dist: aiosqlite>=0.16.0; extra == "full"
|
302
316
|
Requires-Dist: asyncpg>=0.21.0; extra == "full"
|