Skip to content

Commit dcb3324

Browse files
saket0187ninsbl
andauthored
t.list: Add mapset options for t.list (#7631)
* Add mapset options for t.list * do not require a TGIS DB in current mapset --------- Co-authored-by: ninsbl <stefan.blumentrath@gmx.de>
1 parent 8eb0a03 commit dcb3324

6 files changed

Lines changed: 200 additions & 107 deletions

File tree

python/grass/temporal/core.py

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,14 @@
4040
from pathlib import Path
4141

4242
import grass.script as gs
43+
from grass.tools import Tools
4344
from grass.pygrass import messages
4445
from grass.script.utils import decode
4546

4647
from .c_libraries_interface import CLibrariesInterface
4748

4849

50+
tools = Tools()
4951
# Import all supported database backends (sqlite3 imported above)
5052
# Ignore import errors since they are checked later
5153

@@ -497,21 +499,26 @@ def stop_subprocesses() -> None:
497499
atexit.register(stop_subprocesses)
498500

499501

500-
def get_available_temporal_mapsets():
501-
"""Return a list of of mapset names with temporal database driver and names
502-
that are accessible from the current mapset.
502+
def get_available_temporal_mapsets(mapsets: str | None = None):
503+
"""Return a list of of mapset names with temporal database driver and names.
504+
505+
:param mapsets: A string specifying target mapsets ('.' for current, '*'
506+
for all mapsets in the location, or comma-separated names).
507+
If None, defaults to the current search path.
503508
504509
:returns: A dictionary, mapset names are keys, the tuple (driver,
505510
database) are the values
506511
"""
507512
global c_library_interface, message_interface
508513

509-
mapsets = c_library_interface.available_mapsets()
514+
connections = tools.t_connect(flags="p", format="json", mapset=mapsets, quiet=True)
515+
mapsets_list = [conn for conn in connections if all(conn.values())]
510516

511517
tgis_mapsets = {}
512518

513-
for mapset in mapsets:
514-
driver = c_library_interface.get_driver_name(mapset)
519+
for mapset_data in mapsets_list:
520+
mapset = mapset_data["mapset"]
521+
driver = mapset_data["driver"]
515522
database = c_library_interface.get_database_name(mapset)
516523

517524
message_interface.debug(
@@ -1098,8 +1105,8 @@ def _create_tgis_metadata_table(content, dbif=None) -> None:
10981105

10991106

11001107
class SQLDatabaseInterfaceConnection:
1101-
def __init__(self) -> None:
1102-
self.tgis_mapsets = get_available_temporal_mapsets()
1108+
def __init__(self, mapsets: str | None = None) -> None:
1109+
self.tgis_mapsets = get_available_temporal_mapsets(mapsets)
11031110
self.current_mapset = get_current_mapset()
11041111
self.connections = {}
11051112
self.connected = False

python/grass/temporal/list_stds.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,20 @@
2525

2626
import grass.script as gs
2727

28-
from .core import get_available_temporal_mapsets, get_tgis_message_interface, init_dbif
28+
from .core import get_tgis_message_interface, init_dbif
2929
from .datetime_math import time_delta_to_relative_time
30-
from .factory import dataset_factory
3130
from .open_stds import open_old_stds
3231

3332
###############################################################################
3433

3534

3635
def get_dataset_list(
37-
type, temporal_type, columns=None, where=None, order=None, dbif=None
36+
type,
37+
temporal_type,
38+
columns=None,
39+
where=None,
40+
order=None,
41+
dbif=None,
3842
):
3943
"""Return a list of time stamped maps or space time datasets of a specific
4044
temporal type that are registered in the temporal database
@@ -93,20 +97,15 @@ def get_dataset_list(
9397
>>> check = sp.delete()
9498
9599
"""
96-
id = None
97-
sp = dataset_factory(type, id)
98-
99100
dbif, connection_state_changed = init_dbif(dbif)
100101

101-
mapsets = get_available_temporal_mapsets()
102-
103102
result = {}
104103

105-
for mapset in mapsets.keys():
104+
for mapset in dbif.tgis_mapsets:
106105
if temporal_type == "absolute":
107-
table = sp.get_type() + "_view_abs_time"
106+
table = type + "_view_abs_time"
108107
else:
109-
table = sp.get_type() + "_view_rel_time"
108+
table = type + "_view_rel_time"
110109

111110
if columns and columns.find("all") == -1:
112111
sql = "SELECT " + str(columns) + " FROM " + table

temporal/t.list/t.list.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,22 @@ The SQL *where* and *sort* expression will be applied for each temporal
1717
database that was found in accessible mapsets. Hence sorting works only
1818
on mapset basis.
1919

20-
Temporal databases stored in other mapsets can be used as long as they
21-
are in the user's current mapset search path (managed with
22-
[g.mapsets](g.mapsets.md)).
20+
The **mapset** option allows the user to filter the output to one
21+
or multiple specific mapsets, or to query all mapsets in the project regardless
22+
of the current search path. By default (if the **mapset** option is not provided),
23+
Temporal datasets are listed from all mapsets in the user's current search path
24+
(managed with [g.mapsets](g.mapsets.md)).
25+
26+
The **mapset** parameter accepts the following inputs:
27+
`mapset='.'` lists datasets only in the current mapset.
28+
`mapset='*'` lists datasets in all mapsets in the project (location), bypassing
29+
the search path.
30+
`mapset=name1,name2` lists datasets strictly from the explicitly named mapsets,
31+
even if they are outside the current search path.
2332

2433
## EXAMPLES
2534

26-
Obtain the list of space time raster dataset(s):
35+
Obtain the list of space time raster dataset(s) in the current search path:
2736

2837
```sh
2938
t.list strds
@@ -32,6 +41,30 @@ Space time raster datasets with absolute time available in mapset <climate_2000_
3241
tempmean_monthly@climate_2000_2012
3342
```
3443

44+
Obtain the list of space time raster datasets in a specific mapset, even if it is
45+
not in the search path:
46+
47+
```sh
48+
t.list strds mapset=modis2002lst
49+
----------------------------------------------
50+
Space time raster datasets with absolute time available in mapset <modis2002lst>:
51+
mini_set@modis2002lst
52+
```
53+
54+
Obtain the list of space time raster datasets across all mapsets in the project
55+
(location) using '*':
56+
57+
```sh
58+
t.list type=strds mapset='*'
59+
----------------------------------------------
60+
Space time raster datasets with absolute time available in mapset <climate_2000_2012>:
61+
precip_abs@climate_2000_2012
62+
precipitation@climate_2000_2012
63+
tempmean@climate_2000_2012
64+
Space time raster datasets with absolute time available in mapset <modis2002lst>:
65+
mini_set@modis2002lst
66+
```
67+
3568
Obtain the list of space time raster datasets in a specific mapset (Note
3669
that the target mapset must be in the user's search path):
3770

temporal/t.list/t.list.py

Lines changed: 78 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,12 @@
7878
# % guisection: Formatting
7979
# %end
8080

81+
# %option G_OPT_M_MAPSET
82+
# % multiple: yes
83+
# % description: Name of mapsets to list ('.' for current, '*' for all mapsets)
84+
# % guisection: Selection
85+
# %end
86+
8187
# %option G_OPT_F_SEP
8288
# % answer:
8389
# % label: Field separator character between the output columns
@@ -99,15 +105,14 @@
99105
from contextlib import nullcontext
100106

101107
import grass.script as gs
102-
from grass.tools import Tools
103108

104109
############################################################################
105110

106111

107112
def main():
108113

109114
# Get the options
110-
type = options["type"]
115+
stds_type = options["type"]
111116
temporal_type = options["temporaltype"]
112117
columns = options["columns"]
113118
order = options["order"]
@@ -116,6 +121,7 @@ def main():
116121
outpath = options["output"]
117122
colhead = flags["c"]
118123
output_format = options.get("format", "plain")
124+
mapsets = options["mapset"]
119125

120126
if not columns:
121127
columns = "all" if output_format == "json" else "id"
@@ -150,17 +156,20 @@ def main():
150156
elif not separator: # output_format == "plain"
151157
separator = "|"
152158

153-
tools = Tools()
159+
# Lazy import and initialize TGIS
160+
import grass.temporal as tgis
154161

155-
conn = tools.t_connect(flags="p", format="json", mapset=".")
162+
tgis.init(skip_db_init=True)
156163

157-
db_exists = conn[0]["driver"] and conn[0]["database"]
164+
dbif = tgis.SQLDatabaseInterfaceConnection(mapsets=mapsets)
158165

159166
# if no connection is found
160-
if not db_exists:
167+
if not dbif.tgis_mapsets:
161168
if output_format == "plain":
162169
gs.message(
163-
_("No temporal database exists in this mapset. No datasets to list.")
170+
_(
171+
"No temporal database found in the requested mapset(s). No datasets to list."
172+
)
164173
)
165174
with (
166175
open(outpath, "w")
@@ -171,19 +180,11 @@ def main():
171180
out_file.write(json.dumps([], indent=4) + "\n")
172181
return
173182

174-
# Lazy import
175-
import grass.temporal as tgis
176-
177-
# Make sure the temporal database exists
178-
tgis.init()
179-
180-
sp = tgis.dataset_factory(type, None)
181-
dbif = tgis.SQLDatabaseInterfaceConnection()
182183
dbif.connect()
183-
first = True
184184

185185
json_output = []
186186
line_output = []
187+
first = True
187188

188189
if gs.verbosity() > 0 and not outpath and output_format == "plain":
189190
sys.stderr.write("----------------------------------------------\n")
@@ -196,80 +197,73 @@ def main():
196197
):
197198
for ttype in temporal_type.split(","):
198199
time = "absolute time" if ttype == "absolute" else "relative time"
199-
200200
stds_list = tgis.get_dataset_list(
201-
type, ttype, columns, where, order, dbif=dbif
201+
stds_type, ttype, columns, where, order, dbif=dbif
202202
)
203203

204-
mapsets = tgis.get_tgis_c_library_interface().available_mapsets()
205-
206-
for key in mapsets:
207-
if key in stds_list.keys():
208-
rows = stds_list[key]
209-
210-
if rows:
211-
if (
212-
gs.verbosity() > 0
213-
and (not outpath or outpath == "-")
214-
and output_format == "plain"
215-
):
216-
if issubclass(sp.__class__, tgis.AbstractMapDataset):
217-
sys.stderr.write(
218-
_(
219-
"Time stamped %s maps with %s available in mapset "
220-
"<%s>:\n"
221-
)
222-
% (sp.get_type(), time, key)
223-
)
224-
else:
225-
sys.stderr.write(
226-
_(
227-
"Space time %s datasets with %s available in "
228-
"mapset <%s>:\n"
229-
)
230-
% (
231-
sp.get_new_map_instance(None).get_type(),
232-
time,
233-
key,
234-
)
204+
for mapset in dbif.tgis_mapsets:
205+
rows = stds_list.get(mapset)
206+
if rows:
207+
if (
208+
gs.verbosity() > 0
209+
and (not outpath or outpath == "-")
210+
and output_format == "plain"
211+
):
212+
if stds_type in {"raster", "raster_3d", "vector"}:
213+
sys.stderr.write(
214+
_(
215+
"Time stamped %s maps with %s available in mapset "
216+
"<%s>:\n"
235217
)
236-
237-
if output_format == "json":
238-
for row in rows:
239-
json_output.append(dict(row))
240-
241-
elif output_format == "line":
242-
line_output.extend([str(row[0]) for row in rows])
243-
218+
% (stds_type, time, mapset)
219+
)
244220
else:
245-
if (colhead or output_format == "csv") and first:
246-
output = ""
247-
count = 0
248-
for col_key in rows[0].keys():
249-
output += (separator if count > 0 else "") + str(
250-
col_key
221+
sys.stderr.write(
222+
_(
223+
"Space time %s datasets with %s available in "
224+
"mapset <%s>:\n"
225+
)
226+
% (
227+
stds_type,
228+
time,
229+
mapset,
230+
)
231+
)
232+
233+
if output_format == "json":
234+
for row in rows:
235+
json_output.append(dict(row))
236+
237+
elif output_format == "line":
238+
line_output.extend([str(row[0]) for row in rows])
239+
240+
else:
241+
if (colhead or output_format == "csv") and first:
242+
output = ""
243+
count = 0
244+
for col_key in rows[0].keys():
245+
output += (separator if count > 0 else "") + str(
246+
col_key
247+
)
248+
count += 1
249+
out_file.write(f"{output}\n")
250+
first = False
251+
252+
for row in rows:
253+
output = ""
254+
count = 0
255+
for col in row:
256+
# If the database value is None, make it an empty string for csv
257+
if col is None:
258+
cell_value = (
259+
"" if output_format == "csv" else "None"
251260
)
252-
count += 1
253-
out_file.write("{st}\n".format(st=output))
254-
first = False
255-
256-
for row in rows:
257-
output = ""
258-
count = 0
259-
for col in row:
260-
# If the database value is None, make it an empty string for csv
261-
if col is None:
262-
cell_value = (
263-
"" if output_format == "csv" else "None"
264-
)
265-
else:
266-
cell_value = str(col)
267-
268-
output += (
269-
separator if count > 0 else ""
270-
) + cell_value
271-
count += 1
272-
out_file.write("{st}\n".format(st=output))
261+
else:
262+
cell_value = str(col)
263+
264+
output += (separator if count > 0 else "") + cell_value
265+
count += 1
266+
out_file.write("{st}\n".format(st=output))
273267

274268
# Dump the collected JSON and line data
275269
if output_format == "json":

0 commit comments

Comments
 (0)