From 595af10688a3317f276af1123dfae91397124d5c Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Fri, 13 Feb 2026 21:19:22 -0500 Subject: [PATCH 01/12] Add input validation and testing for geometry parameters in project.py Add input validation for 'endpoint', 'pole', and 'azimuth' to check for only one paramter being passed. Add testing to check that appropriate error is raised. --- pygmt/src/project.py | 12 +++++++++++- pygmt/tests/test_project.py | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 47 insertions(+), 2 deletions(-) diff --git a/pygmt/src/project.py b/pygmt/src/project.py index 0b5199b2647..d2372ccb7b8 100644 --- a/pygmt/src/project.py +++ b/pygmt/src/project.py @@ -10,7 +10,7 @@ from pygmt._typing import PathLike, TableLike from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session -from pygmt.exceptions import GMTParameterError +from pygmt.exceptions import GMTInvalidInput, GMTParameterError from pygmt.helpers import ( build_arg_list, fmt_docstring, @@ -229,6 +229,16 @@ def project( # noqa: PLR0913 if kwargs.get("G") is not None and kwargs.get("F") is not None: raise GMTParameterError(at_most_one=["convention", "generate"]) + # Input validation for only one geometry parameter + geometry_params = [ + kwargs.get("A") is not None, + kwargs.get("E", endpoint) is not None, + kwargs.get("T", pole) is not None, + ] + if sum(geometry_params) > 1: + msg = "Must specify only one of 'azimuth', 'endpoint', or 'pole'." + raise GMTInvalidInput(msg) + output_type = validate_output_table_type(output_type, outfile=outfile) column_names = None diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index f6580aa6fa5..f1c28f4da6f 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -10,7 +10,7 @@ import pytest import xarray as xr from pygmt import project -from pygmt.exceptions import GMTParameterError +from pygmt.exceptions import GMTInvalidInput, GMTParameterError from pygmt.helpers import GMTTempFile @@ -90,3 +90,38 @@ def test_project_incorrect_parameters(): with pytest.raises(GMTParameterError): # Using `generate` with `convention` project(center=[0, -1], generate=0.5, convention="xypqrsz") + + +@pytest.mark.parametrize( + ("kwargs"), + [ + { + "center": [0, -1], + "generate": 0.5, + "data": [[0, 0]], + "azimuth": 45, + "endpoint": [0, 1], + }, + { + "center": [0, -1], + "generate": 0.5, + "data": [[0, 0]], + "azimuth": 45, + "pole": [0, 90], + }, + { + "center": [0, -1], + "generate": 0.5, + "data": [[0, 0]], + "endpoint": [0, 1], + "pole": [0, 90], + }, + ], +) +def test_project_geometry_definition_validation(kwargs): + """ + Validate input validation for mutually + exclusive projection geometry parameters. + """ + with pytest.raises(GMTInvalidInput): + project(**kwargs) From e978a2096ff60cb732963b3b3ead2e7ba40efcb3 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Fri, 13 Feb 2026 21:25:48 -0500 Subject: [PATCH 02/12] Fix double brackets --- pygmt/tests/test_project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index f1c28f4da6f..4399bbeffab 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -98,21 +98,21 @@ def test_project_incorrect_parameters(): { "center": [0, -1], "generate": 0.5, - "data": [[0, 0]], + "data": [0, 0], "azimuth": 45, "endpoint": [0, 1], }, { "center": [0, -1], "generate": 0.5, - "data": [[0, 0]], + "data": [0, 0], "azimuth": 45, "pole": [0, 90], }, { "center": [0, -1], "generate": 0.5, - "data": [[0, 0]], + "data": [0, 0], "endpoint": [0, 1], "pole": [0, 90], }, From 320664e75ba7f843b60773e030e0dafc3275dc67 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Fri, 13 Feb 2026 21:28:14 -0500 Subject: [PATCH 03/12] Remove trailing white space --- pygmt/src/project.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/src/project.py b/pygmt/src/project.py index d2372ccb7b8..503e84bfe71 100644 --- a/pygmt/src/project.py +++ b/pygmt/src/project.py @@ -231,9 +231,9 @@ def project( # noqa: PLR0913 # Input validation for only one geometry parameter geometry_params = [ - kwargs.get("A") is not None, - kwargs.get("E", endpoint) is not None, - kwargs.get("T", pole) is not None, + kwargs.get("A") is not None, + kwargs.get("E", endpoint) is not None, + kwargs.get("T", pole) is not None, ] if sum(geometry_params) > 1: msg = "Must specify only one of 'azimuth', 'endpoint', or 'pole'." From 4de1f58f709586707a987fc33b12e1db27313fe1 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sat, 14 Feb 2026 20:56:40 -0500 Subject: [PATCH 04/12] Update pygmt/src/project.py Co-authored-by: Dongdong Tian --- pygmt/src/project.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/pygmt/src/project.py b/pygmt/src/project.py index 503e84bfe71..53bae05261b 100644 --- a/pygmt/src/project.py +++ b/pygmt/src/project.py @@ -236,8 +236,7 @@ def project( # noqa: PLR0913 kwargs.get("T", pole) is not None, ] if sum(geometry_params) > 1: - msg = "Must specify only one of 'azimuth', 'endpoint', or 'pole'." - raise GMTInvalidInput(msg) + raise GMTParameterError(at_most_one=["azimuth", "endpoint", "pole"]) output_type = validate_output_table_type(output_type, outfile=outfile) From 7b3ade65759426e205bd2759bc3d6725b04bd3ea Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Sat, 14 Feb 2026 21:05:58 -0500 Subject: [PATCH 05/12] Remove parametrized test --- pygmt/tests/test_project.py | 38 +++++++++---------------------------- 1 file changed, 9 insertions(+), 29 deletions(-) diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index 4399bbeffab..084cb0662ba 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -92,36 +92,16 @@ def test_project_incorrect_parameters(): project(center=[0, -1], generate=0.5, convention="xypqrsz") -@pytest.mark.parametrize( - ("kwargs"), - [ - { - "center": [0, -1], - "generate": 0.5, - "data": [0, 0], - "azimuth": 45, - "endpoint": [0, 1], - }, - { - "center": [0, -1], - "generate": 0.5, - "data": [0, 0], - "azimuth": 45, - "pole": [0, 90], - }, - { - "center": [0, -1], - "generate": 0.5, - "data": [0, 0], - "endpoint": [0, 1], - "pole": [0, 90], - }, - ], -) -def test_project_geometry_definition_validation(kwargs): +def test_project_geometry_definition_validation(dataframe): """ Validate input validation for mutually exclusive projection geometry parameters. """ - with pytest.raises(GMTInvalidInput): - project(**kwargs) + with pytest.raises(GMTParameterError): + project(center= [0, -1], + generate= 0.5, + data=dataframe, + endpoint=[0, 1], + azimuth=45, + pole=[0, 90],) + From c511e4d4a5437d1d2df0ea840d0dbed175213a21 Mon Sep 17 00:00:00 2001 From: actions-bot <58130806+actions-bot@users.noreply.github.com> Date: Sun, 15 Feb 2026 02:10:07 +0000 Subject: [PATCH 06/12] [format-command] fixes --- pygmt/src/project.py | 2 +- pygmt/tests/test_project.py | 11 ++++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/pygmt/src/project.py b/pygmt/src/project.py index 53bae05261b..bd9ffe73e93 100644 --- a/pygmt/src/project.py +++ b/pygmt/src/project.py @@ -10,7 +10,7 @@ from pygmt._typing import PathLike, TableLike from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session -from pygmt.exceptions import GMTInvalidInput, GMTParameterError +from pygmt.exceptions import GMTParameterError from pygmt.helpers import ( build_arg_list, fmt_docstring, diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index 084cb0662ba..67ba45603db 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -10,7 +10,7 @@ import pytest import xarray as xr from pygmt import project -from pygmt.exceptions import GMTInvalidInput, GMTParameterError +from pygmt.exceptions import GMTParameterError from pygmt.helpers import GMTTempFile @@ -98,10 +98,11 @@ def test_project_geometry_definition_validation(dataframe): exclusive projection geometry parameters. """ with pytest.raises(GMTParameterError): - project(center= [0, -1], - generate= 0.5, + project( + center=[0, -1], + generate=0.5, data=dataframe, endpoint=[0, 1], azimuth=45, - pole=[0, 90],) - + pole=[0, 90], + ) From d5cc70f448f92e216237824385f7e0d464e4c10e Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Fri, 20 Feb 2026 15:38:38 -0500 Subject: [PATCH 07/12] Remove data parameter from test; not needed --- pygmt/tests/test_project.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index 67ba45603db..e4fdc94bc02 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -101,7 +101,6 @@ def test_project_geometry_definition_validation(dataframe): project( center=[0, -1], generate=0.5, - data=dataframe, endpoint=[0, 1], azimuth=45, pole=[0, 90], From 7bdf6a1a04ce010c18d362be039bd206444f609b Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Fri, 20 Feb 2026 15:40:41 -0500 Subject: [PATCH 08/12] Remove unused dataframe variable from test --- pygmt/tests/test_project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index e4fdc94bc02..4ab19e4bb89 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -92,7 +92,7 @@ def test_project_incorrect_parameters(): project(center=[0, -1], generate=0.5, convention="xypqrsz") -def test_project_geometry_definition_validation(dataframe): +def test_project_geometry_definition_validation(): """ Validate input validation for mutually exclusive projection geometry parameters. From 242f63c6426e77784ca114fcfd5ad126b5686236 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Fri, 20 Feb 2026 22:41:56 -0500 Subject: [PATCH 09/12] Update pygmt/src/project.py Co-authored-by: Dongdong Tian --- pygmt/src/project.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/project.py b/pygmt/src/project.py index bd9ffe73e93..046f8a0f95f 100644 --- a/pygmt/src/project.py +++ b/pygmt/src/project.py @@ -231,7 +231,7 @@ def project( # noqa: PLR0913 # Input validation for only one geometry parameter geometry_params = [ - kwargs.get("A") is not None, + kwargs.get("A", azimuth) is not None, kwargs.get("E", endpoint) is not None, kwargs.get("T", pole) is not None, ] From ec0bf74683ca94f797bcda464e8cff8da668b303 Mon Sep 17 00:00:00 2001 From: Will Schlitzer Date: Fri, 20 Feb 2026 22:42:08 -0500 Subject: [PATCH 10/12] Update pygmt/tests/test_project.py Co-authored-by: Dongdong Tian --- pygmt/tests/test_project.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index 4ab19e4bb89..349926de0fb 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -96,12 +96,12 @@ def test_project_geometry_definition_validation(): """ Validate input validation for mutually exclusive projection geometry parameters. - """ + kwdict = {"center": [0, -1], "data": dataframe} with pytest.raises(GMTParameterError): - project( - center=[0, -1], - generate=0.5, - endpoint=[0, 1], - azimuth=45, - pole=[0, 90], - ) + project(endpoint=[0, 1], azimuth=45, **kwdict) + with pytest.raises(GMTParameterError): + project(endpoint=[0, 1], pole=[0, 90], **kwdict) + with pytest.raises(GMTParameterError): + project(pole=[0, 90], azimuth=45, **kwdict) + with pytest.raises(GMTParameterError): + project(pole=[0, 90], azimuth=45, endpoint=[0, 1], **kwdict) From 48acc7ce3b49a45e84061a475bf5b24f98b64176 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 21 Feb 2026 12:19:53 +0800 Subject: [PATCH 11/12] Apply suggestion from @seisman --- pygmt/tests/test_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index 349926de0fb..86ef0730ba1 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -94,8 +94,8 @@ def test_project_incorrect_parameters(): def test_project_geometry_definition_validation(): """ - Validate input validation for mutually - exclusive projection geometry parameters. + Validate input validation for mutually exclusive projection geometry parameters. + """ kwdict = {"center": [0, -1], "data": dataframe} with pytest.raises(GMTParameterError): project(endpoint=[0, 1], azimuth=45, **kwdict) From 3abedeecf5f6c988af48ccb85963b43f9e800813 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sat, 21 Feb 2026 12:21:00 +0800 Subject: [PATCH 12/12] Final fix --- pygmt/tests/test_project.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/tests/test_project.py b/pygmt/tests/test_project.py index 86ef0730ba1..4d00709c039 100644 --- a/pygmt/tests/test_project.py +++ b/pygmt/tests/test_project.py @@ -92,7 +92,7 @@ def test_project_incorrect_parameters(): project(center=[0, -1], generate=0.5, convention="xypqrsz") -def test_project_geometry_definition_validation(): +def test_project_geometry_definition_validation(dataframe): """ Validate input validation for mutually exclusive projection geometry parameters. """ @@ -104,4 +104,4 @@ def test_project_geometry_definition_validation(): with pytest.raises(GMTParameterError): project(pole=[0, 90], azimuth=45, **kwdict) with pytest.raises(GMTParameterError): - project(pole=[0, 90], azimuth=45, endpoint=[0, 1], **kwdict) + project(pole=[0, 90], azimuth=45, endpoint=[0, 1], **kwdict)