Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v.out.ogr: Fix exporting vector layers from a location whose CRS has no EPSG code #3869

Open
wants to merge 32 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
5cffa26
Adds basic unit tests to v.out.ogr
ldesousa Jun 16, 2024
47d256b
Closes #2187
ldesousa Jun 17, 2024
8da3982
Restricts use of assertModule method
ldesousa Jun 17, 2024
88464da
Merge branch 'test-v-out-ogr' into issue#2187
ldesousa Jun 17, 2024
36caea6
Code farmatting
ldesousa Jun 17, 2024
1cb6632
Moves WKT file to data folder in unit test
ldesousa Jun 17, 2024
0b95ec4
Improves code standards with pylint suggestions
ldesousa Jun 18, 2024
08f7492
Merge branch 'test-v-out-ogr' into issue#2187
ldesousa Jun 18, 2024
5a73b5f
Improves code standards with pylint suggestions
ldesousa Jun 18, 2024
35ba769
Renames methods and adds doc strings
ldesousa Jun 18, 2024
6bdc3c9
Merge branch 'test-v-out-ogr' into issue#2187
ldesousa Jun 18, 2024
ebf444c
Renames methods and adds doc strings
ldesousa Jun 18, 2024
9b293b3
Adds basic unit tests to v.out.ogr
ldesousa Jun 16, 2024
93f5429
Restricts use of assertModule method
ldesousa Jun 17, 2024
280997f
Improves code standards with pylint suggestions
ldesousa Jun 18, 2024
a2ae200
Renames methods and adds doc strings
ldesousa Jun 18, 2024
fc2c253
Merge branch 'test-v-out-ogr' of github.com:ldesousa/grass into test-…
ldesousa Jun 19, 2024
1c83ffa
Corrects typo
ldesousa Jun 19, 2024
3235dfc
Merge branch 'test-v-out-ogr' into issue#2187
ldesousa Jun 19, 2024
1c14af9
Merge branch 'main' of github.com:OSGeo/grass into test-v-out-ogr
ldesousa Jun 19, 2024
f98aead
Merge branch 'test-v-out-ogr' into issue#2187
ldesousa Jun 19, 2024
3e80eca
Merge branch 'main' into issue#2187
echoix Jun 26, 2024
d05b093
Merge branch 'main' into issue#2187
ldesousa Jul 26, 2024
77fc48b
Updates vector/v.out.ogr/testsuite/test_v_out_ogr.py with Ruff sugges…
ldesousa Jul 31, 2024
a076bbc
Updates vector/v.out.ogr/testsuite/test_v_out_ogr.py with Ruff sugges…
ldesousa Jul 31, 2024
d1f70b7
Merge branch 'main' into issue#2187
ldesousa Jul 31, 2024
6844064
Merges main branch
ldesousa Aug 1, 2024
16d61e0
Merge branch 'issue#2187' of github.com:ldesousa/grass into issue#2187
ldesousa Aug 1, 2024
b46fb05
Update vector/v.out.ogr/testsuite/test_v_out_ogr.py
ldesousa Aug 29, 2024
1c96ce0
Merge branch 'main' into issue#2187
echoix Sep 3, 2024
6fd87bc
Merge branch 'OSGeo:main' into issue#2187
ldesousa Sep 6, 2024
f59f324
Extra comments required in PR review
ldesousa Sep 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion vector/v.out.ogr/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,6 @@ int main(int argc, char *argv[])
inwkt = NULL;
}
proj_destroy(source_crs);
Ogr_projection = NULL;
ldesousa marked this conversation as resolved.
Show resolved Hide resolved
if (inwkt) {
char *inwkttmp = inwkt;

Expand Down
63 changes: 63 additions & 0 deletions vector/v.out.ogr/testsuite/data/ESRI54052.wkt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
BOUNDCRS[
SOURCECRS[
PROJCRS["unknown",
BASEGEOGCRS["wgs84",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS_1984",6378137,298.257223563,
LENGTHUNIT["metre",1,
ID["EPSG",9001]]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8901]]],
CONVERSION["unnamed",
METHOD["Interrupted Goode Homolosine"],
PARAMETER["Longitude of natural origin",0,
ANGLEUNIT["degree",0.0174532925199433],
ID["EPSG",8802]],
PARAMETER["False easting",0,
LENGTHUNIT["metre",1],
ID["EPSG",8806]],
PARAMETER["False northing",0,
LENGTHUNIT["metre",1],
ID["EPSG",8807]]],
CS[Cartesian,2],
AXIS["easting",east,
ORDER[1],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]],
AXIS["northing",north,
ORDER[2],
LENGTHUNIT["metre",1,
ID["EPSG",9001]]]]],
TARGETCRS[
GEOGCRS["WGS 84",
DATUM["World Geodetic System 1984",
ELLIPSOID["WGS 84",6378137,298.257223563,
LENGTHUNIT["metre",1]]],
PRIMEM["Greenwich",0,
ANGLEUNIT["degree",0.0174532925199433]],
CS[ellipsoidal,2],
AXIS["latitude",north,
ORDER[1],
ANGLEUNIT["degree",0.0174532925199433]],
AXIS["longitude",east,
ORDER[2],
ANGLEUNIT["degree",0.0174532925199433]],
ID["EPSG",4326]]],
ABRIDGEDTRANSFORMATION["Transformation from wgs84 to WGS84",
METHOD["Position Vector transformation (geog2D domain)",
ID["EPSG",9606]],
PARAMETER["X-axis translation",0,
ID["EPSG",8605]],
PARAMETER["Y-axis translation",0,
ID["EPSG",8606]],
PARAMETER["Z-axis translation",0,
ID["EPSG",8607]],
PARAMETER["X-axis rotation",0,
ID["EPSG",8608]],
PARAMETER["Y-axis rotation",0,
ID["EPSG",8609]],
PARAMETER["Z-axis rotation",0,
ID["EPSG",8610]],
PARAMETER["Scale difference",1,
ID["EPSG",8611]]]]
169 changes: 169 additions & 0 deletions vector/v.out.ogr/testsuite/test_v_out_ogr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
"""Test of v.out.ogr

@author Luís Moreira de Sousa
"""

from pathlib import Path
from shutil import rmtree
import grass.script as gs
from grass.gunittest.case import TestCase


class TestOgrExport(TestCase):

# Vector map in NC test dataset
test_map = "boundary_county"

# Result of import tests
temp_import = "test_ogr_import_map"

# Temporary location
temp_location = "temp_location"

# Temporary Homolosine map
temp_54052 = "temp_rand.gpkg"

# Temporary environment file
session_file = ""

# Column on which to test v.univar
univar_col = "PERIMETER"

# Output of v.univar
univar_string = """n=926
nmissing=0
nnull=0
min=9.64452
max=3.70609e+06
range=3.70608e+06
sum=1.1223e+08
mean=121199
mean_abs=121199
population_stddev=342855
population_variance=1.17549e+11
population_coeff_variation=2.82886
sample_stddev=343040
sample_variance=1.17676e+11
kurtosis=33.681
skewness=4.86561
"""

@classmethod
def setUpClass(cls):
"""Use temporary region settings"""
cls.use_temp_region()

@classmethod
def tearDownClass(cls):
"""!Remove the temporary region"""
ldesousa marked this conversation as resolved.
Show resolved Hide resolved
cls.del_temp_region()

def tearDown(self):

# Remove maps in temp mapset
self.runModule(
"g.remove", type="vector", flags="f", pattern=f"{self.temp_import}*"
)
# Remove temporary files
for p in Path(".").glob(f"{self.test_map}*"):
ldesousa marked this conversation as resolved.
Show resolved Hide resolved
p.unlink()
for p in Path(".").glob(f"{self.temp_54052}*"):
ldesousa marked this conversation as resolved.
Show resolved Hide resolved
p.unlink()
if len(self.session_file) > 0:
Path(self.session_file).unlink()

# Remove temporary location
env = gs.parse_command("g.gisenv")
dbase = env["GISDBASE"].replace("'", "").replace(";", "")
rmtree(f"{dbase}/{self.temp_location}", ignore_errors=True)

def test_gpkg_format(self):
"""Tests output to GeoPackage format"""

self.assertModule(
"v.out.ogr",
"Export to GeoPackage Format",
input=self.test_map,
output=f"{self.test_map}.gpkg",
format="GPKG",
)

# Import back to verify
self.runModule(
"v.in.ogr",
input=f"{self.test_map}.gpkg",
output=self.temp_import,
)

self.runModule("g.region", vector=self.temp_import)

self.assertVectorFitsUnivar(
map=self.temp_import,
reference=self.univar_string,
column=self.univar_col,
precision=1e-8,
)

def test_shp_format(self):
"""Tests output to Shapefile format"""

self.assertModule(
"v.out.ogr",
"Export to Shapefile Format",
input=self.test_map,
output=f"{self.test_map}.shp",
format="ESRI_Shapefile",
)

# Import back to verify
self.runModule(
"v.in.ogr",
input=f"{self.test_map}.shp",
output=self.temp_import,
)

self.runModule("g.region", vector=self.temp_import)

self.assertVectorFitsUnivar(
map=self.temp_import,
reference=self.univar_string,
column=self.univar_col,
precision=1e-8,
)

def test_no_epsg_crs(self):
"""Tests output from a location/project lacking an EPSG code"""

# Record original location to use corect GISDBASE
env_orig = gs.parse_command("g.gisenv")

# Create new location with CRS without EPSG code
gs.run_command(
"g.proj", wkt="data/ESRI54052.wkt", location=self.temp_location, flags="c"
)

# Create new session to avoid temporary region
self.session_file, env_new = gs.core.create_environment(
env_orig["GISDBASE"].replace("'", "").replace(";", ""),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would use a comment or two about why these two replace calls are needed. Are the characters an issue? Why are the characters there? How is the original GISDBASE working with them?

(Same for line 77.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those characters are included in the variable string, e.g. '/home/lads/GRASSDATA';. The tests do not fail if you don't remove them, however, the following call to rmtree then does not remove the actual temporary location. Garbage is thus left behind in the file system.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry to keep this hanging, but I find it both puzzling and concerning that GISDBASE retrieved by g.gisenv has quotes and a semicolon. Are you sure that's what you have there? Can you please directly run g.gisenv in the same or similar session you run the tests?

GRASS nc_basic_spm_grass7/user1:script > g.gisenv 
GISDBASE=/home/vpetras/grassdata
LOCATION_NAME=nc_basic_spm_grass7
MAPSET=user1
GUI=text
PID=1094462
GRASS nc_basic_spm_grass7/user1:script > python -c "import grass.script as gs; print(gs.gisenv())"
{'GISDBASE': '/home/vpetras/grassdata', 'LOCATION_NAME': 'nc_basic_spm_grass7', 'MAPSET': 'user1', 'GUI': 'text', 'PID': '1094462'}

And can you print from the test? (You may need to fail the test to get a print.)

self.assertFalse(env_orig)

self.temp_location,
"PERMANENT",
)

# Creates a random layer to test output
gs.run_command("v.random", output="temp_rand", npoints=3, env=env_new)

# Test output of a vector with non-EPSG CRS
gs.run_command(
"v.out.ogr",
input="temp_rand",
output=self.temp_54052,
format="GPKG",
dsco="a_srs=ESRI:54052",
env=env_new,
)


if __name__ == "__main__":
from grass.gunittest.main import test

test()
Loading