diff --git a/python/grass/gunittest/utils.py b/python/grass/gunittest/utils.py index 4b3f45a22e7..a8a00c608dd 100644 --- a/python/grass/gunittest/utils.py +++ b/python/grass/gunittest/utils.py @@ -55,6 +55,11 @@ def do_doctest_gettext_workaround() -> None: This should be considered for the future. The second option is to define dummy underscore function and one other function which creates the right environment to satisfy all. This is done by this function. + + The default display hook assigns the last printed value to ``_`` in builtins, + replacing the gettext function. The display hook is replaced both in + ``sys.displayhook`` and in ``sys.__displayhook__`` because doctest sets + ``sys.displayhook`` to ``sys.__displayhook__`` before running each example. """ def new_displayhook(string: str | None) -> None: @@ -67,6 +72,7 @@ def new_translator(string: str) -> str: return string sys.displayhook = new_displayhook + sys.__displayhook__ = new_displayhook import builtins diff --git a/python/grass/script/core.py b/python/grass/script/core.py index d40b9904753..4bfe0772f9a 100644 --- a/python/grass/script/core.py +++ b/python/grass/script/core.py @@ -202,8 +202,8 @@ def get_commands(*, env=None): >>> cmds = list(get_commands()[0]) >>> cmds.sort() - >>> cmds[:5] - ['d.barscale', 'd.colorlist', 'd.colortable', 'd.correlate', 'd.erase'] + >>> "g.region" in cmds + True """ if not env: env = os.environ @@ -520,7 +520,7 @@ def start_command( >>> p = start_command("g.gisenv", stdout=subprocess.PIPE) >>> print(p) # doctest: +ELLIPSIS - <...Popen object at 0x...> + <...Popen...> >>> print(p.communicate()[0]) # doctest: +SKIP GISDBASE='/opt/grass-data'; LOCATION_NAME='spearfish60'; @@ -627,7 +627,7 @@ def pipe_command(*args, **kwargs): >>> p = pipe_command("g.gisenv") >>> print(p) # doctest: +ELLIPSIS - <....Popen object at 0x...> + <...Popen...> >>> print(p.communicate()[0]) # doctest: +SKIP GISDBASE='/opt/grass-data'; LOCATION_NAME='spearfish60'; @@ -761,7 +761,6 @@ def write_command(*args, **kwargs): ... stdin="%s|%s" % (635818.8, 221342.4), ... output="view_point", ... ) - 0 See :func:`start_command()` for details about parameters and usage. @@ -1147,8 +1146,8 @@ def tempname(length: int, lowercase: bool = False) -> str: :Example: .. code-block:: pycon - >>> tempname(12) - 'tmp_MxMa1kAS13s9' + >>> tempname(12) # doctest: +ELLIPSIS + 'tmp_...' .. seealso:: functions :func:`~grass.script.utils.append_uuid()`, :func:`~grass.script.utils.append_random()`, @@ -2282,11 +2281,8 @@ def version(): .. code-block:: pycon - >>> print(version()) - {'proj4': '4.8.0', 'geos': '3.3.5', 'libgis_revision': '52468', - 'libgis_date': '2012-07-27 22:53:30 +0200 (Fri, 27 Jul 2012)', - 'version': '7.0.svn', 'date': '2012', 'gdal': '2.0dev', - 'revision': '53670'} + >>> print(version()) # doctest: +ELLIPSIS + {'version': '...', 'date': '...', 'revision': '...', ...} """ data = parse_command("g.version", flags="rge", errors="ignore") diff --git a/python/grass/script/db.py b/python/grass/script/db.py index 006ad7c7b99..d1688a0fb76 100644 --- a/python/grass/script/db.py +++ b/python/grass/script/db.py @@ -37,11 +37,9 @@ def db_describe(table, env=None, **args): .. code-block:: pycon >>> run_command("g.copy", vector="firestations,myfirestations") - 0 >>> db_describe("myfirestations") # doctest: +ELLIPSIS - {'nrows': 71, 'cols': [['cat', 'INTEGER', '20'], ... 'ncols': 22} + {'ncols': 22, 'nrows': 71, 'cols': [['cat', 'INTEGER', '20'], ...]} >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") - 0 :param str table: table name :param list args: @@ -83,11 +81,9 @@ def db_table_exist(table, env=None, **args): (check db_connection()). >>> run_command("g.copy", vector="firestations,myfirestations") - 0 >>> db_table_exist("myfirestations") True >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") - 0 :param str table: table name :param args: @@ -119,8 +115,8 @@ def db_connection(force=False, env=None): :Example: .. code-block:: pycon - >>> db_connection() - {'group': '', 'schema': '', 'driver': 'sqlite', 'database': '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db'} + >>> db_connection(force=True) + {'driver': 'sqlite', 'database': '$GISDBASE/$LOCATION_NAME/$MAPSET/sqlite/sqlite.db', 'schema': '', 'group': ''} :param force: True to set up default DB connection if not defined :param env: environment @@ -150,7 +146,6 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): .. code-block:: pycon >>> run_command("g.copy", vector="firestations,myfirestations") - 0 >>> db_select(sql="SELECT cat,CITY FROM myfirestations WHERE cat < 4") (('1', 'Morrisville'), ('2', 'Morrisville'), ('3', 'Apex')) @@ -161,7 +156,6 @@ def db_select(sql=None, filename=None, table=None, env=None, **args): >>> db_select(table="myfirestations") # doctest: +ELLIPSIS (('1', '24', 'Morrisville #3', ... 'HS2A', '1.37')) >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") - 0 :param str sql: SQL statement to perform (or None) :param str filename: name of file with SQL statements (or None) @@ -208,12 +202,10 @@ def db_table_in_vector(table, mapset=".", env=None): It returns None if no vectors are connected to the table. >>> run_command("g.copy", vector="firestations,myfirestations") - 0 - >>> db_table_in_vector("myfirestations") - ['myfirestations@user1'] + >>> db_table_in_vector("myfirestations") # doctest: +ELLIPSIS + ['myfirestations@...'] >>> db_table_in_vector("mfirestations") >>> run_command("g.remove", flags="f", type="vector", name="myfirestations") - 0 :param str table: name of table to query :param env: environment diff --git a/python/grass/script/imagery.py b/python/grass/script/imagery.py index 9917e9f905f..d3411240b88 100644 --- a/python/grass/script/imagery.py +++ b/python/grass/script/imagery.py @@ -46,19 +46,27 @@ def group_to_dict( :Example: .. code-block:: pycon - >>> run_command("g.copy", raster="lsat7_2000_10,lsat7_2000_10") - >>> run_command("r.support", raster="lsat7_2000_10", semantic_label="L8_1") - >>> run_command("g.copy", raster="lsat7_2000_20,lsat7_2000_20") - >>> run_command("r.support", raster="lsat7_2000_20", semantic_label="L8_2") - >>> run_command("g.copy", raster="lsat7_2000_30,lsat7_2000_30") - >>> run_command("r.support", raster="lsat7_2000_30", semantic_label="L8_3") - >>> run_command("i.group", group="L8_group", - >>> input="lsat7_2000_10,lsat7_2000_20,lsat7_2000_30") + >>> import grass.script as gs + >>> gs.run_command("g.copy", raster="lsat7_2002_10,lsat7_2002_10") + >>> gs.run_command("r.support", map="lsat7_2002_10", semantic_label="L8_1") + >>> gs.run_command("g.copy", raster="lsat7_2002_20,lsat7_2002_20") + >>> gs.run_command("r.support", map="lsat7_2002_20", semantic_label="L8_2") + >>> gs.run_command("g.copy", raster="lsat7_2002_30,lsat7_2002_30") + >>> gs.run_command("r.support", map="lsat7_2002_30", semantic_label="L8_3") + >>> gs.run_command( + ... "i.group", + ... group="L8_group", + ... input="lsat7_2002_10,lsat7_2002_20,lsat7_2002_30", + ... ) >>> group_to_dict("L8_group") # doctest: +ELLIPSIS - {"L8_1": "lsat7_2000_10", ... "L8_3": "lsat7_2000_30"} - >>> run_command("g.remove", flags="f", type="group", name="L8_group") - >>> run_command("g.remove", flags="f", type="raster", - >>> name="lsat7_2000_10,lsat7_2000_20,lsat7_2000_30") + {'L8_1': 'lsat7_2002_10@...', ... 'L8_3': 'lsat7_2002_30@...'} + >>> gs.run_command("g.remove", flags="f", type="group", name="L8_group") + >>> gs.run_command( + ... "g.remove", + ... flags="f", + ... type="raster", + ... name="lsat7_2002_10,lsat7_2002_20,lsat7_2002_30", + ... ) :param str imagery_group_name: Name of the imagery group to process (or None) :param str subgroup: Name of the imagery sub-group to process (or None) diff --git a/python/grass/script/raster.py b/python/grass/script/raster.py index 01092ce9029..8460a7a716a 100644 --- a/python/grass/script/raster.py +++ b/python/grass/script/raster.py @@ -84,8 +84,9 @@ def raster_info(map, env=None): :Example: .. code-block:: pycon - >>> raster_info("elevation") # doctest: +ELLIPSIS - {'creator': '"helena"', 'cols': '1500' ... 'south': 215000.0} + >>> raster_info("elevation") # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + {'north': 228500.0, 'south': 215000.0, ... 'cols': '1500', ... 'creator': + '"helena"', ...} :param str map: map name :param env: environment @@ -246,7 +247,7 @@ def raster_what(map, coord, env=None, localized=False): """Interface to r.what >>> raster_what("elevation", [[640000, 228000]]) - [{'elevation': {'color': '255:214:000', 'label': '', 'value': '102.479'}}] + [{'elevation': {'value': '102.479', 'label': '', 'color': '255:214:000'}}] :param str map: the map name :param list coord: a list of list containing all the point that you want to query @@ -302,9 +303,12 @@ class MaskManager: raster which represents the mask. The mask is deactivated at the end of the context by the context manager and the raster is removed. + >>> import grass.script as gs + >>> gs.run_command("g.region", raster="elevation") >>> with gs.MaskManager(): - ... gs.run_command("r.mask", raster="state_boundary") - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.run_command("r.mask", raster="lakes") + ... gs.parse_command("r.univar", map="elevation", format="json")["n"] + 36011 The *mask_name* can be a name of an existing raster map and in that case, that raster map is used directly as is. If the raster map does not exist, @@ -314,19 +318,22 @@ class MaskManager: The mask is disabled at the end of the context, but the raster map is not removed. - >>> with gs.MaskManager(mask_name="state_boundary"): - ... gs.parse_command("r.univar", map="elevation", format="json") + >>> with gs.MaskManager(mask_name="lakes@PERMANENT"): + ... gs.parse_command("r.univar", map="elevation", format="json")["n"] + 36011 Example using explicit activate and deactivate: >>> manager = gs.MaskManager() - >>> manager.activate() + >>> manager.activate() # doctest: +ELLIPSIS + <...MaskManager object at ...> >>> try: ... # Create mask with r.mask - ... gs.run_command("r.mask", raster="state_boundary") - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.run_command("r.mask", raster="lakes") + ... gs.parse_command("r.univar", map="elevation", format="json")["n"] ... finally: ... manager.deactivate() + 36011 Note the difference between using the name of an existing raster map directly @@ -353,11 +360,9 @@ class MaskManager: >>> with gs.MaskManager() as manager: ... gs.run_command( - "r.mapcalc", expression=f"{manager.mask_name} = row() < col()" - ) - ... gs.run_command( - "r.mapcalc", expression=f"masked_elevation = elevation" - ) + ... "r.mapcalc", expression=f"{manager.mask_name} = row() < col()" + ... ) + ... gs.run_command("r.mapcalc", expression="masked_elevation = elevation") In the background, this class manages the `GRASS_MASK` environment variable. It modifies the current system environment or the one provided. It does not @@ -375,7 +380,9 @@ class MaskManager: ... env=manager.env, ... ) ... gs.run_command( - ... "r.mapcalc", expression=f"masked_elevation = elevation", env=manager.env + ... "r.mapcalc", + ... expression="masked_elevation_env = elevation", + ... env=manager.env, ... ) """ @@ -471,8 +478,11 @@ class RegionManager: Example with explicit region parameters: + >>> import grass.script as gs + >>> gs.run_command("g.region", raster="elevation") >>> with gs.RegionManager(n=226000, s=222000, w=634000, e=638000): - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 160000 Example matching a raster map's region: @@ -483,19 +493,22 @@ class RegionManager: >>> with gs.RegionManager(): ... gs.run_command("g.region", n=226000, s=222000, w=634000, e=638000) - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 160000 Example using a saved region: >>> gs.run_command("g.region", save="study_area", s=1000, n=1100, w=1000, e=1100) >>> with gs.RegionManager(region="study_area"): - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 100 Example using :py:meth:`~grass.script.raster.RegionManager.set_region`: >>> with gs.RegionManager() as manager: ... manager.set_region(n=226000, s=222000, w=634000, e=638000) - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 160000 Example using :py:meth:`~grass.script.raster.RegionManager.save` to store the temporarily modified region under a persistent name so it can be reused after the context exits: @@ -506,9 +519,12 @@ class RegionManager: Example using explicit activate and deactivate: >>> manager = gs.RegionManager(raster="elevation") - >>> manager.activate() + >>> manager.activate() # doctest: +ELLIPSIS + <...RegionManager object at ...> >>> try: - ... gs.run_command("r.slope.aspect", elevation="elevation", slope="slope") + ... gs.run_command( + ... "r.slope.aspect", elevation="elevation", slope="slope_activated" + ... ) ... finally: ... manager.deactivate() @@ -614,26 +630,34 @@ class RegionManagerEnv: Example with explicit region parameters: + >>> import grass.script as gs + >>> gs.run_command("g.region", raster="elevation") >>> with gs.RegionManagerEnv(n=226000, s=222000, w=634000, e=638000): - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 160000 Example using a saved region: - >>> gs.run_command("g.region", save="study_area", s=1000, n=1100, w=1000, e=1100) - >>> with gs.RegionManagerEnv(region="study_area"): - ... gs.parse_command("r.univar", map="elevation", format="json") + >>> gs.run_command( + ... "g.region", save="study_area_env", s=1000, n=1100, w=1000, e=1100 + ... ) + >>> with gs.RegionManagerEnv(region="study_area_env"): + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 100 Example with :py:meth:`.set_region`: >>> with gs.RegionManagerEnv() as manager: ... manager.set_region(n=226000, s=222000, w=634000, e=638000) - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 64 This is identical to: >>> with gs.RegionManagerEnv() as manager: ... manager.env["GRASS_REGION"] = gs.region_env() - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] + 1010600 Example using :py:meth:`.save`: to store the temporarily modified region under a persistent name so it can be reused after the context exits: @@ -644,12 +668,14 @@ class RegionManagerEnv: Example using explicit activate and deactivate: >>> manager = gs.RegionManagerEnv(raster="elevation") - >>> manager.activate() + >>> manager.activate() # doctest: +ELLIPSIS + <...RegionManagerEnv object at ...> >>> try: ... manager.set_region(n=226000, s=222000, w=634000, e=638000) - ... gs.parse_command("r.univar", map="elevation", format="json") + ... gs.parse_command("r.univar", map="elevation", format="json")["cells"] ... finally: ... manager.deactivate() + 160000 .. caution:: diff --git a/python/grass/script/raster3d.py b/python/grass/script/raster3d.py index 39305f97848..185b622b7c4 100644 --- a/python/grass/script/raster3d.py +++ b/python/grass/script/raster3d.py @@ -32,11 +32,11 @@ def raster3d_info(map, env=None): :Example: .. code-block:: pycon + >>> import grass.script as gs >>> mapcalc3d("volume = row() + col() + depth()") >>> raster3d_info("volume") # doctest: +ELLIPSIS - {'vertical_units': '"units"', 'tbres': 1.0, ... 'south': 185000.0} - >>> run_command("g.remove", flags="f", type="raster_3d", name="volume") - 0 + {'north': ..., 'south': ..., ... 'vertical_units': '"units"', ...} + >>> gs.run_command("g.remove", flags="f", type="raster_3d", name="volume") :param str map: map name :param env: environment diff --git a/python/grass/script/task.py b/python/grass/script/task.py index f6561354247..491ccf7b3fc 100644 --- a/python/grass/script/task.py +++ b/python/grass/script/task.py @@ -535,27 +535,16 @@ def command_info(cmd): with entries for description, keywords, usage, flags, and parameters, e.g. - >>> command_info("g.tempfile") # doctest: +NORMALIZE_WHITESPACE - {'keywords': ['general', 'support'], 'params': [{'gisprompt': False, - 'multiple': False, 'name': 'pid', 'guidependency': '', 'default': '', - 'age': None, 'required': True, 'value': '', 'label': '', 'guisection': '', - 'key_desc': [], 'values': [], 'values_desc': [], 'prompt': None, - 'hidden': False, 'element': None, 'type': 'integer', 'description': - 'Process id to use when naming the tempfile'}], 'flags': [{'description': - "Dry run - don't create a file, just prints it's file name", 'value': - False, 'label': '', 'guisection': '', 'suppress_required': False, - 'hidden': False, 'name': 'd'}, {'description': 'Print usage summary', - 'value': False, 'label': '', 'guisection': '', 'suppress_required': False, - 'hidden': False, 'name': 'help'}, {'description': 'Verbose module output', - 'value': False, 'label': '', 'guisection': '', 'suppress_required': False, - 'hidden': False, 'name': 'verbose'}, {'description': 'Quiet module output', - 'value': False, 'label': '', 'guisection': '', 'suppress_required': False, - 'hidden': False, 'name': 'quiet'}], 'description': "Creates a temporary - file and prints it's file name.", 'usage': 'g.tempfile pid=integer [--help] - [--verbose] [--quiet]'} - - >>> command_info("v.buffer") - ['vector', 'geometry', 'buffer'] + >>> info = command_info("g.tempfile") + >>> info["description"] + "Creates a temporary file and prints it's file name." + >>> info["keywords"] + ['general', 'support', 'scripts'] + >>> info["usage"] + 'g.tempfile pid=integer [--help] [--verbose] [--quiet]' + + >>> command_info("v.buffer")["keywords"] + ['vector', 'buffer', 'area', 'circle', 'geometry', 'line', 'grow', 'shrink'] :param str cmd: the command to query """ diff --git a/python/grass/script/testsuite/test_script_doctests.py b/python/grass/script/testsuite/test_script_doctests.py index cc202cd942e..2a457f63c86 100644 --- a/python/grass/script/testsuite/test_script_doctests.py +++ b/python/grass/script/testsuite/test_script_doctests.py @@ -33,6 +33,17 @@ def load_tests(loader, tests, ignore): grass.gunittest.utils.do_doctest_gettext_workaround() # this should be called at some top level tests.addTests(doctest.DocTestSuite(garray)) + for name in ( + "core", + "db", + "imagery", + "raster", + "raster3d", + "task", + "utils", + "vector", + ): + tests.addTests(doctest.DocTestSuite(f"grass.script.{name}")) return tests diff --git a/python/grass/script/utils.py b/python/grass/script/utils.py index 29f31b63237..9ae6629408d 100644 --- a/python/grass/script/utils.py +++ b/python/grass/script/utils.py @@ -269,12 +269,10 @@ def decode(bytes_: AnyStr, encoding: str | None = None) -> str: Example ------- - >>> decode(b"S\xc3\xbcdtirol") - u'Südtirol' + >>> decode(b"S\\xc3\\xbcdtirol") + 'Südtirol' >>> decode("Südtirol") - u'Südtirol' - >>> decode(1234) - u'1234' + 'Südtirol' """ if isinstance(bytes_, str): return bytes_ @@ -298,12 +296,10 @@ def encode(string: AnyStr, encoding: str | None = None) -> bytes: Example ------- - >>> encode(b"S\xc3\xbcdtirol") - b'S\xc3\xbcdtirol' - >>> decode("Südtirol") - b'S\xc3\xbcdtirol' - >>> decode(1234) - b'1234' + >>> encode(b"S\\xc3\\xbcdtirol") + b'S\\xc3\\xbcdtirol' + >>> encode("Südtirol") + b'S\\xc3\\xbcdtirol' """ if isinstance(string, bytes): return string @@ -686,7 +682,8 @@ def append_node_pid(name): The returned string is a name usable for vectors, tables, and columns (vector legal name) as long as provided argument *name* is. - >>> append_node_pid("tmp_raster_1") + >>> append_node_pid("tmp_raster_1") # doctest: +ELLIPSIS + 'tmp_raster_1_...' .. note:: @@ -719,7 +716,8 @@ def append_uuid(name): For a random name of a given shorter size, see :func:`append_random()`. - >>> append_uuid("tmp") + >>> append_uuid("tmp") # doctest: +ELLIPSIS + 'tmp_...' .. note:: @@ -733,8 +731,10 @@ def append_uuid(name): def append_random(name, suffix_length=None, total_length=None): """Add a random part to of a specified length to a name (string) - >>> append_random("tmp", 8) - >>> append_random("tmp", total_length=16) + >>> append_random("tmp", 8) # doctest: +ELLIPSIS + 'tmp_...' + >>> append_random("tmp", total_length=16) # doctest: +ELLIPSIS + 'tmp_...' .. note:: diff --git a/python/grass/script/vector.py b/python/grass/script/vector.py index 1b905faf14d..7ceacfe3aed 100644 --- a/python/grass/script/vector.py +++ b/python/grass/script/vector.py @@ -39,7 +39,8 @@ def vector_db(map, env=None, **kwargs): .. code-block:: pycon >>> vector_db("geology") # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - {1: {'layer': 1, ... 'table': 'geology'}} + {1: {'layer': 1, 'name': 'geology', 'table': 'geology', 'key': 'cat', + 'database': '...', 'driver': 'sqlite'}} :param str map: vector map :param kwargs: other v.db.connect's arguments @@ -103,12 +104,14 @@ def vector_columns(map, layer=None, getDict=True, env=None, **kwargs): database table connected to a vector map (interface to `v.info -c`). >>> vector_columns("geology", getDict=True) # doctest: +NORMALIZE_WHITESPACE - {'PERIMETER': {'index': 2, 'type': 'DOUBLE PRECISION'}, 'GEOL250_': - {'index': 3, 'type': 'INTEGER'}, 'SHAPE_area': {'index': 6, 'type': - 'DOUBLE PRECISION'}, 'onemap_pro': {'index': 1, 'type': 'DOUBLE - PRECISION'}, 'SHAPE_len': {'index': 7, 'type': 'DOUBLE PRECISION'}, - 'cat': {'index': 0, 'type': 'INTEGER'}, 'GEOL250_ID': {'index': 4, 'type': - 'INTEGER'}, 'GEO_NAME': {'index': 5, 'type': 'CHARACTER'}} + {'cat': {'type': 'INTEGER', 'index': 0}, + 'onemap_pro': {'type': 'DOUBLE PRECISION', 'index': 1}, + 'PERIMETER': {'type': 'DOUBLE PRECISION', 'index': 2}, + 'GEOL250_': {'type': 'INTEGER', 'index': 3}, + 'GEOL250_ID': {'type': 'INTEGER', 'index': 4}, + 'GEO_NAME': {'type': 'CHARACTER', 'index': 5}, + 'SHAPE_area': {'type': 'DOUBLE PRECISION', 'index': 6}, + 'SHAPE_len': {'type': 'DOUBLE PRECISION', 'index': 7}} >>> vector_columns("geology", getDict=False) # doctest: +NORMALIZE_WHITESPACE ['cat', @@ -171,9 +174,8 @@ def vector_info_topo(map, layer=1, env=None): .. code-block:: pycon >>> vector_info_topo("geology") # doctest: +NORMALIZE_WHITESPACE - {'lines': 0, 'centroids': 1832, 'boundaries': 3649, 'points': 0, - 'primitives': 5481, 'islands': 907, 'nodes': 2724, 'map3d': False, - 'areas': 1832} + {'nodes': 2724, 'points': 0, 'lines': 0, 'boundaries': 3649, 'centroids': 1832, + 'areas': 1832, 'islands': 907, 'primitives': 5481, 'map3d': False} :param str map: map name :param int layer: layer number @@ -197,7 +199,8 @@ def vector_info(map, layer=1, env=None): .. code-block:: pycon >>> vector_info("geology") # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE - {'comment': '', 'projection': 'Lambert Conformal Conic' ... 'south': 10875.8272320917} + {'name': 'geology', 'mapset': 'PERMANENT', ... 'projection': 'Lambert Conformal + Conic', ... 'south': 10875.8272320917, ...} :param str map: map name :param int layer: layer number diff --git a/python/grass/temporal/abstract_space_time_dataset.py b/python/grass/temporal/abstract_space_time_dataset.py index 576b261281e..fb0ec25539b 100644 --- a/python/grass/temporal/abstract_space_time_dataset.py +++ b/python/grass/temporal/abstract_space_time_dataset.py @@ -1747,13 +1747,22 @@ def _update_where_statement_by_spatial_extent( .. code-block:: pycon - >>> import grass.script as gs + >>> import grass.temporal as tgis + >>> strds = tgis.SpaceTimeRasterDataset("test@PERMANENT") >>> where = None - >>> spatial_extent = gs.parse_command("g.region", flags="ug3") - >>> _update_where_statement_by_spatial_extent( + >>> spatial_extent = { + ... "n": "1", + ... "s": "0", + ... "e": "1", + ... "w": "0", + ... "b": "0", + ... "t": "1", + ... "projection": "1", + ... } + >>> strds._update_where_statement_by_spatial_extent( ... where, spatial_extent, "overlaps" ... ) - ((north > 0 AND south < 1 AND east > 0 AND west < 1)) + '((north > 0 AND south < 1 AND east > 0 AND west < 1))' """ # initialized WHERE statement diff --git a/python/grass/temporal/base.py b/python/grass/temporal/base.py index 3504844999f..c708cae3a6f 100644 --- a/python/grass/temporal/base.py +++ b/python/grass/temporal/base.py @@ -51,7 +51,8 @@ def serialize(self, type, table, where=None): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> t = DictSQLSerializer() >>> t.D["id"] = "soil@PERMANENT" >>> t.D["name"] = "soil" @@ -60,13 +61,13 @@ def serialize(self, type, table, where=None): >>> t.D["creation_time"] = datetime(2001, 1, 1) >>> t.D["modification_time"] = datetime(2001, 1, 1) >>> t.serialize(type="SELECT", table="raster_base") - ('SELECT name , creator , creation_time , modification_time , mapset , id FROM raster_base ;\\n', ()) + ('SELECT id , name , mapset , creator , creation_time , modification_time FROM raster_base ;\\n', ()) >>> t.serialize(type="INSERT", table="raster_base") - ('INSERT INTO raster_base ( name ,creator ,creation_time ,modification_time ,mapset ,id ) VALUES (? ,? ,? ,? ,? ,?) ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT')) + ('INSERT INTO raster_base ( id ,name ,mapset ,creator ,creation_time ,modification_time ) VALUES (? ,? ,? ,? ,? ,?) ;\\n', ('soil@PERMANENT', 'soil', 'PERMANENT', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0))) >>> t.serialize(type="UPDATE", table="raster_base") - ('UPDATE raster_base SET name = ? ,creator = ? ,creation_time = ? ,modification_time = ? ,mapset = ? ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT')) + ('UPDATE raster_base SET id = ? ,name = ? ,mapset = ? ,creator = ? ,creation_time = ? ,modification_time = ? ;\\n', ('soil@PERMANENT', 'soil', 'PERMANENT', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0))) >>> t.serialize(type="UPDATE ALL", table="raster_base") - ('UPDATE raster_base SET name = ? ,creator = ? ,creation_time = ? ,modification_time = ? ,mapset = ? ,id = ? ;\\n', ('soil', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil@PERMANENT')) + ('UPDATE raster_base SET id = ? ,name = ? ,mapset = ? ,creator = ? ,creation_time = ? ,modification_time = ? ;\\n', ('soil@PERMANENT', 'soil', 'PERMANENT', 'soeren', datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0))) :param type: must be SELECT. INSERT, UPDATE :param table: The name of the table to select, insert or update @@ -213,7 +214,8 @@ class SQLDatabaseInterface(DictSQLSerializer): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> t = SQLDatabaseInterface("raster", "soil@PERMANENT") >>> t.mapset = get_current_mapset() >>> t.D["name"] = "soil" @@ -225,21 +227,21 @@ class SQLDatabaseInterface(DictSQLSerializer): >>> t.get_is_in_db_statement() "SELECT id FROM raster WHERE id = 'soil@PERMANENT';\\n" >>> t.get_select_statement() - ("SELECT creation_time , mapset , name , creator FROM raster WHERE id = 'soil@PERMANENT';\\n", ()) + ("SELECT name , mapset , creator , creation_time FROM raster WHERE id = 'soil@PERMANENT';\\n", ()) >>> t.get_select_statement_mogrified() - "SELECT creation_time , mapset , name , creator FROM raster WHERE id = 'soil@PERMANENT';\\n" + "SELECT name , mapset , creator , creation_time FROM raster WHERE id = 'soil@PERMANENT';\\n" >>> t.get_insert_statement() - ('INSERT INTO raster ( creation_time ,mapset ,name ,creator ) VALUES (? ,? ,? ,?) ;\\n', (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren')) + ('INSERT INTO raster ( name ,mapset ,creator ,creation_time ) VALUES (? ,? ,? ,?) ;\\n', ('soil', 'PERMANENT', 'soeren', datetime.datetime(2001, 1, 1, 0, 0))) >>> t.get_insert_statement_mogrified() - "INSERT INTO raster ( creation_time ,mapset ,name ,creator ) VALUES ('2001-01-01 00:00:00' ,'PERMANENT' ,'soil' ,'soeren') ;\\n" + "INSERT INTO raster ( name ,mapset ,creator ,creation_time ) VALUES ('soil' ,'PERMANENT' ,'soeren' ,'2001-01-01 00:00:00') ;\\n" >>> t.get_update_statement() - ("UPDATE raster SET creation_time = ? ,mapset = ? ,name = ? ,creator = ? WHERE id = 'soil@PERMANENT';\\n", (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren')) + ("UPDATE raster SET name = ? ,mapset = ? ,creator = ? ,creation_time = ? WHERE id = 'soil@PERMANENT';\\n", ('soil', 'PERMANENT', 'soeren', datetime.datetime(2001, 1, 1, 0, 0))) >>> t.get_update_statement_mogrified() - "UPDATE raster SET creation_time = '2001-01-01 00:00:00' ,mapset = 'PERMANENT' ,name = 'soil' ,creator = 'soeren' WHERE id = 'soil@PERMANENT';\\n" + "UPDATE raster SET name = 'soil' ,mapset = 'PERMANENT' ,creator = 'soeren' ,creation_time = '2001-01-01 00:00:00' WHERE id = 'soil@PERMANENT';\\n" >>> t.get_update_all_statement() - ("UPDATE raster SET creation_time = ? ,mapset = ? ,name = ? ,creator = ? WHERE id = 'soil@PERMANENT';\\n", (datetime.datetime(2001, 1, 1, 0, 0), 'PERMANENT', 'soil', 'soeren')) + ("UPDATE raster SET name = ? ,mapset = ? ,creator = ? ,creation_time = ? WHERE id = 'soil@PERMANENT';\\n", ('soil', 'PERMANENT', 'soeren', datetime.datetime(2001, 1, 1, 0, 0))) >>> t.get_update_all_statement_mogrified() - "UPDATE raster SET creation_time = '2001-01-01 00:00:00' ,mapset = 'PERMANENT' ,name = 'soil' ,creator = 'soeren' WHERE id = 'soil@PERMANENT';\\n" + "UPDATE raster SET name = 'soil' ,mapset = 'PERMANENT' ,creator = 'soeren' ,creation_time = '2001-01-01 00:00:00' WHERE id = 'soil@PERMANENT';\\n" """ # noqa: E501 @@ -590,7 +592,8 @@ class DatasetBase(SQLDatabaseInterface): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> t = DatasetBase( ... "raster", ... "soil@PERMANENT", @@ -961,7 +964,8 @@ class STDSBase(DatasetBase): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> t = STDSBase( ... "stds", ... "soil@PERMANENT", @@ -1152,7 +1156,8 @@ class AbstractSTDSRegister(SQLDatabaseInterface): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> t = AbstractSTDSRegister("raster", "soil@PERMANENT", "A@P,B@P,C@P") >>> t.id 'soil@PERMANENT' diff --git a/python/grass/temporal/c_libraries_interface.py b/python/grass/temporal/c_libraries_interface.py index be9e1b2d400..637091b7afd 100644 --- a/python/grass/temporal/c_libraries_interface.py +++ b/python/grass/temporal/c_libraries_interface.py @@ -1275,20 +1275,16 @@ class CLibrariesInterface(RPCServerBase): ... res=10.0, ... res3=10.0, ... ) - 0 >>> tgis.init() >>> gscript.run_command( ... "r.mapcalc", expression="test = 1", overwrite=True, quiet=True ... ) - 0 >>> gscript.run_command( ... "r3.mapcalc", expression="test = 1", overwrite=True, quiet=True ... ) - 0 >>> gscript.run_command( ... "v.random", output="test", n=10, overwrite=True, quiet=True ... ) - 0 >>> gscript.run_command( ... "r.timestamp", ... map="test", @@ -1296,7 +1292,6 @@ class CLibrariesInterface(RPCServerBase): ... overwrite=True, ... quiet=True, ... ) - 0 >>> gscript.run_command( ... "r3.timestamp", ... map="test", @@ -1304,7 +1299,6 @@ class CLibrariesInterface(RPCServerBase): ... overwrite=True, ... quiet=True, ... ) - 0 >>> gscript.run_command( ... "v.timestamp", ... map="test", @@ -1312,7 +1306,6 @@ class CLibrariesInterface(RPCServerBase): ... overwrite=True, ... quiet=True, ... ) - 0 # Check mapsets >>> ciface = tgis.CLibrariesInterface() @@ -1326,12 +1319,13 @@ class CLibrariesInterface(RPCServerBase): >>> print(check) True >>> ciface.read_raster_info("test", tgis.get_current_mapset()) - {'rows': 8, 'north': 80.0, 'min': 1, 'datatype': 'CELL', 'max': 1, 'ewres': 10.0, 'cols': 12, 'west': 0.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0} + {'north': 80.0, 'south': 0.0, 'east': 120.0, 'west': 0.0, 'nsres': 10.0, 'ewres': 10.0, 'rows': 8, 'cols': 12, 'datatype': 'CELL', 'min': 1, 'max': 1} >>> info = ciface.read_raster_full_info("test", tgis.get_current_mapset()) >>> info # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE - {u'tbres': 1.0, ... 'keyword': 'generated by r.mapcalc', - u'bottom': 0.0, 'end_time': None, 'title': 'test', u'south': 0.0} + {'name': 'test', 'mapset': '...', ..., 'tbres': 1.0, ... + 'keyword': 'generated by r.mapcalc', 'date': ..., 'title': 'test', ... + 'end_time': None} >>> info["start_time"] datetime.datetime(1995, 3, 12, 10, 34, 40) @@ -1362,7 +1356,7 @@ class CLibrariesInterface(RPCServerBase): >>> print(check) True >>> ciface.read_raster3d_info("test", tgis.get_current_mapset()) - {'tbres': 1.0, 'rows': 8, 'north': 80.0, 'bottom': 0.0, 'datatype': 'DCELL', 'max': 1.0, 'top': 1.0, 'min': 1.0, 'cols': 12, 'depths': 1, 'west': 0.0, 'ewres': 10.0, 'east': 120.0, 'nsres': 10.0, 'south': 0.0} + {'north': 80.0, 'south': 0.0, 'east': 120.0, 'west': 0.0, 'nsres': 10.0, 'ewres': 10.0, 'tbres': 1.0, 'rows': 8, 'cols': 12, 'depths': 1, 'top': 1.0, 'bottom': 0.0, 'datatype': 'DCELL', 'min': 1.0, 'max': 1.0} >>> check = ciface.has_raster3d_timestamp("test", tgis.get_current_mapset()) >>> print(check) True @@ -1436,22 +1430,22 @@ class CLibrariesInterface(RPCServerBase): >>> location = ciface.get_location() >>> gisdbase = ciface.get_gisdbase() - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... - >>> ciface.fatal_error() # doctest: +ELLIPSIS, +NORMALIZE_WHITESPACE + >>> ciface.fatal_error() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): raise FatalError("Exception raised: " + str(e) + " Message: " + message) FatalError: Exception raised: ... diff --git a/python/grass/temporal/core.py b/python/grass/temporal/core.py index fc365bed0dc..c20d97076cd 100644 --- a/python/grass/temporal/core.py +++ b/python/grass/temporal/core.py @@ -357,7 +357,7 @@ def set_raise_on_error(raise_exp: bool = True): >>> tgis.set_raise_on_error(True) False - >>> msgr.fatal("Ohh no no no!") + >>> msgr.fatal("Ohh no no no!") # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): File "__init__.py", line 241, in fatal raise FatalError(message) diff --git a/python/grass/temporal/metadata.py b/python/grass/temporal/metadata.py index f892230b00e..b55f52204c0 100644 --- a/python/grass/temporal/metadata.py +++ b/python/grass/temporal/metadata.py @@ -38,7 +38,8 @@ class RasterMetadataBase(SQLDatabaseInterface): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = RasterMetadataBase( ... table="metadata", ... ident="soil@PERMANENT", @@ -324,7 +325,8 @@ class RasterMetadata(RasterMetadataBase): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = RasterMetadata( ... ident="soil@PERMANENT", ... datatype="CELL", @@ -451,7 +453,8 @@ class Raster3DMetadata(RasterMetadataBase): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = Raster3DMetadata( ... ident="soil@PERMANENT", ... datatype="FCELL", @@ -606,7 +609,8 @@ class VectorMetadata(SQLDatabaseInterface): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = VectorMetadata( ... ident="lidar@PERMANENT", ... is_3d=True, @@ -968,7 +972,8 @@ class STDSMetadataBase(SQLDatabaseInterface): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = STDSMetadataBase( ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" ... ) @@ -1168,7 +1173,8 @@ class for strds and str3ds datasets .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = STDSRasterMetadataBase( ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" ... ) @@ -1395,12 +1401,14 @@ class STRDSMetadata(STDSRasterMetadataBase): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() + >>> mapset = tgis.get_current_mapset() >>> meta = STRDSMetadata( - ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" + ... ident="soils@" + mapset, title="Soils", description="Soils 1950 - 2010" ... ) - >>> meta.id - 'soils@PERMANENT' + >>> meta.id == "soils@" + mapset + True >>> meta.title 'Soils' >>> meta.description @@ -1506,6 +1514,10 @@ def get_semantic_labels(self): # band names supported from TGIS DB version 3 return None + if self.get_raster_register() is None: + # Without a register table there are no maps to get the labels from. + return None + sql = "SELECT distinct semantic_label FROM %s WHERE %s.id " % ( "raster_metadata", "raster_metadata", @@ -1590,7 +1602,8 @@ class STR3DSMetadata(STDSRasterMetadataBase): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = STR3DSMetadata( ... ident="soils@PERMANENT", title="Soils", description="Soils 1950 - 2010" ... ) @@ -1746,7 +1759,8 @@ class STVDSMetadata(STDSMetadataBase): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> meta = STVDSMetadata( ... ident="lidars@PERMANENT", ... title="LIDARS", diff --git a/python/grass/temporal/space_time_datasets.py b/python/grass/temporal/space_time_datasets.py index 4dc9bf6315d..c1e45e18625 100644 --- a/python/grass/temporal/space_time_datasets.py +++ b/python/grass/temporal/space_time_datasets.py @@ -76,23 +76,20 @@ class RasterDataset(AbstractMapDataset): >>> import grass.script as gs >>> import grass.temporal as tgis - >>> init() + >>> tgis.init() >>> gs.use_temp_region() >>> gs.run_command( ... "g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0 ... ) - 0 >>> gs.run_command( ... "r.mapcalc", ... overwrite=True, ... quiet=True, ... expression="strds_map_test_case = 1", ... ) - 0 >>> gs.run_command( ... "r.timestamp", map="strds_map_test_case", date="15 jan 1999", quiet=True ... ) - 0 >>> mapset = tgis.get_current_mapset() >>> name = "strds_map_test_case" >>> identifier = "%s@%s" % (name, mapset) @@ -127,11 +124,11 @@ class RasterDataset(AbstractMapDataset): | East-west resolution:....... 10.0 | Minimum value:.............. 1.0 | Maximum value:.............. 1.0 + | Semantic label:............. None >>> gs.run_command( ... "r.timestamp", map="strds_map_test_case", date="2 years", quiet=True ... ) - 0 >>> rmap.read_timestamp_from_grass() True >>> rmap.get_temporal_extent_as_tuple() @@ -173,7 +170,6 @@ class RasterDataset(AbstractMapDataset): False >>> gs.run_command("g.remove", flags="f", type="raster", name=name, quiet=True) - 0 >>> gs.del_temp_region() """ @@ -487,7 +483,8 @@ class Raster3DDataset(AbstractMapDataset): .. code-block:: pycon >>> import grass.script as gs - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> gs.use_temp_region() >>> gs.run_command( ... "g.region", @@ -500,22 +497,19 @@ class Raster3DDataset(AbstractMapDataset): ... res=10.0, ... res3=10.0, ... ) - 0 >>> gs.run_command( ... "r3.mapcalc", ... overwrite=True, ... quiet=True, ... expression="str3ds_map_test_case = 1", ... ) - 0 >>> gs.run_command( ... "r3.timestamp", ... map="str3ds_map_test_case", ... date="15 jan 1999", ... quiet=True, ... ) - 0 - >>> mapset = get_current_mapset() + >>> mapset = tgis.get_current_mapset() >>> name = "str3ds_map_test_case" >>> identifier = "%s@%s" % (name, mapset) >>> r3map = Raster3DDataset(identifier) @@ -555,7 +549,6 @@ class Raster3DDataset(AbstractMapDataset): >>> gs.run_command( ... "r3.timestamp", map="str3ds_map_test_case", date="2 years", quiet=True ... ) - 0 >>> r3map.read_timestamp_from_grass() True >>> r3map.get_temporal_extent_as_tuple() @@ -598,7 +591,6 @@ class Raster3DDataset(AbstractMapDataset): >>> gs.run_command( ... "g.remove", flags="f", type="raster_3d", name=name, quiet=True ... ) - 0 >>> gs.del_temp_region() """ @@ -870,12 +862,12 @@ class VectorDataset(AbstractMapDataset): .. code-block:: pycon >>> import grass.script as gs - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> gs.use_temp_region() >>> gs.run_command( ... "g.region", n=80.0, s=0.0, e=120.0, w=0.0, t=1.0, b=0.0, res=10.0 ... ) - 0 >>> gs.run_command( ... "v.random", ... overwrite=True, @@ -887,12 +879,10 @@ class VectorDataset(AbstractMapDataset): ... column="elevation", ... quiet=True, ... ) - 0 >>> gs.run_command( ... "v.timestamp", map="stvds_map_test_case", date="15 jan 1999", quiet=True ... ) - 0 - >>> mapset = get_current_mapset() + >>> mapset = tgis.get_current_mapset() >>> name = "stvds_map_test_case" >>> identifier = "%s@%s" % (name, mapset) >>> vmap = VectorDataset(identifier) @@ -927,7 +917,6 @@ class VectorDataset(AbstractMapDataset): >>> gs.run_command( ... "v.timestamp", map="stvds_map_test_case", date="2 years", quiet=True ... ) - 0 >>> vmap.read_timestamp_from_grass() True >>> vmap.get_temporal_extent_as_tuple() @@ -966,7 +955,6 @@ class VectorDataset(AbstractMapDataset): >>> vmap.is_time_relative() False >>> gs.run_command("g.remove", flags="f", type="vector", name=name, quiet=True) - 0 >>> gs.del_temp_region() """ diff --git a/python/grass/temporal/spatial_extent.py b/python/grass/temporal/spatial_extent.py index e1859bb4407..dc383c5e3de 100644 --- a/python/grass/temporal/spatial_extent.py +++ b/python/grass/temporal/spatial_extent.py @@ -83,7 +83,8 @@ class SpatialExtent(SQLDatabaseInterface): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> extent = SpatialExtent( ... table="raster_spatial_extent", ... ident="soil@PERMANENT", diff --git a/python/grass/temporal/spatio_temporal_relationships.py b/python/grass/temporal/spatio_temporal_relationships.py index 5b515dccf15..08d6aa0c1b0 100644 --- a/python/grass/temporal/spatio_temporal_relationships.py +++ b/python/grass/temporal/spatio_temporal_relationships.py @@ -141,12 +141,12 @@ class SpatioTemporalTopologyBuilder: (0, 1) ('PRECEDES', (1, 2)) (1, 2) - ('PRECEDES', (2, 3)) ('EQUAL', (1, 2)) + ('PRECEDES', (2, 3)) (2, 3) ('FOLLOWS', (1, 2)) - ('PRECEDES', (3, 4)) ('EQUAL', (2, 3)) + ('PRECEDES', (3, 4)) (3, 4) ('FOLLOWS', (2, 3)) ('EQUAL', (3, 4)) @@ -180,12 +180,12 @@ class SpatioTemporalTopologyBuilder: (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2001, 1, 1, 0, 0)) ('PRECEDES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0))) (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0)) - ('PRECEDES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('EQUAL', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0))) + ('PRECEDES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)) ('FOLLOWS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0))) - ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('EQUAL', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) + ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)) ('FOLLOWS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('EQUAL', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) @@ -225,10 +225,10 @@ class SpatioTemporalTopologyBuilder: ('STARTS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('PRECEDES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)) - ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0))) - ('FINISHES', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) + ('FINISHES', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('STARTS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) + ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0))) (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)) ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('DURING', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) @@ -261,28 +261,28 @@ class SpatioTemporalTopologyBuilder: ... if key not in ["NEXT", "PREV"]: ... print((key, m[key][0].get_temporal_extent_as_tuple())) (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2002, 1, 1, 0, 0)) - ('OVERLAPS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('STARTS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) + ('OVERLAPS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('PRECEDES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0)) - ('OVERLAPS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) - ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0))) - ('FINISHES', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('DURING', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) + ('FINISHES', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('STARTS', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) + ('OVERLAPS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) + ('PRECEDES', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0))) (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0)) - ('OVERLAPS', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0))) ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) - ('FINISHES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('DURING', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) + ('FINISHES', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('STARTS', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) + ('OVERLAPS', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0))) (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0)) + ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) ('OVERLAPPED', (datetime.datetime(2001, 1, 1, 0, 0), datetime.datetime(2004, 1, 1, 0, 0))) ('DURING', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) ('FINISHES', (datetime.datetime(2002, 1, 1, 0, 0), datetime.datetime(2005, 1, 1, 0, 0))) ('STARTS', (datetime.datetime(2003, 1, 1, 0, 0), datetime.datetime(2006, 1, 1, 0, 0))) - ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2003, 1, 1, 0, 0))) >>> mapsA = [] >>> mapsB = [] @@ -313,19 +313,19 @@ class SpatioTemporalTopologyBuilder: ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)) + ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))) - ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)) - ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))) ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) - ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 4), datetime.datetime(2000, 1, 1, 0, 0, 6))) ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) + ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))) + ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 4), datetime.datetime(2000, 1, 1, 0, 0, 6))) (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)) - ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 4), datetime.datetime(2000, 1, 1, 0, 0, 6))) ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) ('EQUAL', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))) + ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 4), datetime.datetime(2000, 1, 1, 0, 0, 6))) >>> mapsA = [] >>> for i in range(4): @@ -348,13 +348,13 @@ class SpatioTemporalTopologyBuilder: ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3)) - ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2))) + ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) ('PRECEDES', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))) (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4)) - ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))) ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0), datetime.datetime(2000, 1, 1, 0, 0, 2))) ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) + ('OVERLAPS', (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5))) (datetime.datetime(2000, 1, 1, 0, 0, 3), datetime.datetime(2000, 1, 1, 0, 0, 5)) ('FOLLOWS', (datetime.datetime(2000, 1, 1, 0, 0, 1), datetime.datetime(2000, 1, 1, 0, 0, 3))) ('OVERLAPPED', (datetime.datetime(2000, 1, 1, 0, 0, 2), datetime.datetime(2000, 1, 1, 0, 0, 4))) diff --git a/python/grass/temporal/temporal_algebra.py b/python/grass/temporal/temporal_algebra.py index a0b0cde9b8f..1cfa7967922 100644 --- a/python/grass/temporal/temporal_algebra.py +++ b/python/grass/temporal/temporal_algebra.py @@ -1894,16 +1894,16 @@ def set_granularity(self, maplistA, maplistB, toperator="l", topolist=["EQUAL"]) ... print( ... map.get_id() + " - start: " + str(start) + " end: " + str(end) ... ) - a1@B - start: 0 end: 2 a0@B - start: 0 end: 2 - a3@B - start: 2 end: 4 + a1@B - start: 0 end: 2 a2@B - start: 2 end: 4 - a5@B - start: 4 end: 6 + a3@B - start: 2 end: 4 a4@B - start: 4 end: 6 - a7@B - start: 6 end: 8 + a5@B - start: 4 end: 6 a6@B - start: 6 end: 8 - a9@B - start: 8 end: 10 + a7@B - start: 6 end: 8 a8@B - start: 8 end: 10 + a9@B - start: 8 end: 10 :raises SyntaxError: If an unpermitted temporal relation name is used in ``topolist`` """ diff --git a/python/grass/temporal/temporal_extent.py b/python/grass/temporal/temporal_extent.py index c6ed6d3b5a5..3993352c328 100644 --- a/python/grass/temporal/temporal_extent.py +++ b/python/grass/temporal/temporal_extent.py @@ -38,7 +38,9 @@ class TemporalExtent(SQLDatabaseInterface): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() + >>> from datetime import datetime >>> A = TemporalExtent( ... table="raster_absolute_time", ... ident="soil@PERMANENT", @@ -1084,7 +1086,9 @@ class STDSAbsoluteTime(AbsoluteTemporalExtent): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() + >>> from datetime import datetime >>> A = STDSAbsoluteTime( ... table="strds_absolute_time", ... ident="strds@PERMANENT", @@ -1232,7 +1236,8 @@ class RelativeTemporalExtent(TemporalExtent): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> A = RelativeTemporalExtent( ... table="raster_relative_time", ... ident="soil@PERMANENT", @@ -1359,7 +1364,8 @@ class STDSRelativeTime(RelativeTemporalExtent): .. code-block:: pycon - >>> init() + >>> import grass.temporal as tgis + >>> tgis.init() >>> A = STDSRelativeTime( ... table="strds_relative_time", ... ident="strds@PERMANENT", diff --git a/python/grass/temporal/temporal_granularity.py b/python/grass/temporal/temporal_granularity.py index 1f3d3d875aa..55f90479d4c 100644 --- a/python/grass/temporal/temporal_granularity.py +++ b/python/grass/temporal/temporal_granularity.py @@ -121,7 +121,7 @@ def get_time_tuple_function(maps): .. code-block:: pycon >>> from grass.temporal.abstract_map_dataset import AbstractMapDataset - >>> maps = AbstractMapDataset() + >>> maps = [AbstractMapDataset()] >>> get_time_tuple_function(maps).__name__ '_get_map_time_tuple' @@ -1181,11 +1181,11 @@ def gran_to_gran(from_gran, to_gran="days", shell: bool = False): >>> tgis.gran_to_gran("1 month", "1 day", True) 30.436875 - >>> tgis.gran_to_gran("10 year", "1 hour") - '87658.2 hours' + >>> tgis.gran_to_gran("10 year", "1 hour") # doctest: +ELLIPSIS + '87658.2... hours' - >>> tgis.gran_to_gran("10 year", "1 minute") - '5259492.0 minutes' + >>> tgis.gran_to_gran("10 year", "1 minute") # doctest: +ELLIPSIS + '5259492.0... minutes' >>> tgis.gran_to_gran("6 months", "1 day") '182.62125 days' diff --git a/python/grass/temporal/testsuite/test_temporal_doctests.py b/python/grass/temporal/testsuite/test_temporal_doctests.py index 608bf9fff38..9df0aba94c8 100644 --- a/python/grass/temporal/testsuite/test_temporal_doctests.py +++ b/python/grass/temporal/testsuite/test_temporal_doctests.py @@ -3,7 +3,6 @@ """ import doctest -import sys import grass.gunittest.case import grass.gunittest.main @@ -28,8 +27,7 @@ def load_tests(loader, tests, ignore): tests.addTests(doctest.DocTestSuite(tgis.base)) tests.addTests(doctest.DocTestSuite(tgis.core)) tests.addTests(doctest.DocTestSuite(tgis.datetime_math)) - # Unexpected error here - # tests.addTests(doctest.DocTestSuite(tgis.list_stds)) + tests.addTests(doctest.DocTestSuite(tgis.list_stds)) tests.addTests(doctest.DocTestSuite(tgis.metadata)) tests.addTests(doctest.DocTestSuite(tgis.register)) tests.addTests(doctest.DocTestSuite(tgis.space_time_datasets)) @@ -51,8 +49,4 @@ def load_tests(loader, tests, ignore): if __name__ == "__main__": - # Temporary deactivated for Python 3 cause it stalls - if sys.version_info[0] >= 3: - pass - else: - grass.gunittest.main.test() + grass.gunittest.main.test()