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

pygrass: add get_json_dict function #2937

Open
wants to merge 19 commits into
base: main
Choose a base branch
from
Open

Conversation

ninsbl
Copy link
Member

@ninsbl ninsbl commented Apr 26, 2023

This PR adds a get_json_dict function to the pygrass Module interface.

Motivation is to make it easier to create JSON intput to the actinia REST API for GRASS GIS.

Here is a usage example:

import json
from grass.pygrass.modules.interface import Module

json.dumps(Module("r.info", map="elevation", run_=False).get_json_dict())

Suggestions for changes are most welcome...

@ninsbl ninsbl added enhancement New feature or request Python Related code is in Python labels Apr 26, 2023
@ninsbl ninsbl added this to the 8.4.0 milestone Apr 26, 2023
@ninsbl ninsbl marked this pull request as draft May 1, 2023 14:31
@ninsbl
Copy link
Member Author

ninsbl commented Jun 21, 2023

@pesekon2 Do you have any opinion on the addition? You added actinia export to the modeller lately...

@wenzeslaus wenzeslaus modified the milestones: 8.4.0, Future Apr 27, 2024
@github-actions github-actions bot added libraries tests Related to Test Suite labels May 30, 2024
ninsbl and others added 2 commits May 30, 2024 13:11
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
@ninsbl ninsbl marked this pull request as ready for review May 30, 2024 11:11
@ninsbl ninsbl modified the milestones: Future, 8.4.0 May 30, 2024
@ninsbl ninsbl changed the title WIP: pygrass: add get_json_dict function pygrass: add get_json_dict function May 30, 2024
Comment on lines 83 to 91
Module(
"r.slope.aspect",
elevation="elevation",
slope="slope",
aspect="aspect",
overwrite=True,
verbose=True,
run_=False,
).get_json_dict(export="GTiff")
Copy link
Member

Choose a reason for hiding this comment

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

Nothing against smoke tests in general, but these tests are unnecessary simple. Please add assertions to move it beyond smoke tests. It does not really tell what is the expected output.

@@ -53,6 +53,44 @@ def test_rsun(self):
out.close()


class TestModulesJsonDictExport(TestCase):
Copy link
Member

Choose a reason for hiding this comment

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

Consider using pytest for these test. No data needed. Assert functionality suited for for plain values.

Copy link
Member

Choose a reason for hiding this comment

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

And we can run them faster/in parallel! (I was exploring making pytest run for windows and macOS the other day, but still had problems making it find the pytest I installed on the windows CI)

Copy link
Member Author

Choose a reason for hiding this comment

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

This test case is now removed and replaced with pytest in new file: pygrass_modules_interface_json_test.py which has assertations. Hope that is roughly along your lines of thought...

@ninsbl ninsbl requested a review from wenzeslaus May 31, 2024 20:32
Copy link
Member

@wenzeslaus wenzeslaus left a comment

Choose a reason for hiding this comment

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

Looking at the actual concept here, why this is actually needed? We already have the same JSON emitted from the tools themselves with --json:

grass --tmp-project XY --exec python
>>> import subprocess
>>> import json
>>> json.loads(subprocess.run(["r.info", "map=elevation", "--json"], capture_output=True).stdout)
{'module': 'r.info', 'id': 'r.info_1804289383', 'inputs': [{'param': 'map', 'value': 'elevation'}]}

This PR's code:

>>> from grass.pygrass.modules.interface import Module
>>> Module("r.info", map="elevation", run_=False).get_json_dict()
{'module': 'r.info', 'id': 'r_info_bb8b711437c149fdb00e1a4ccdb77839', 'inputs': [{'param': 'map', 'value': 'elevation'}]}

Difference:

grass --tmp-project XY --exec r.info map=elevation --json | jq > old.json
grass --tmp-project XY --exec python -c \
    'from grass.pygrass.modules.interface import Module; import json; print(json.dumps(Module("r.info", map="elevation", run_=False).get_json_dict()))' \
    | jq > new.json
diff -u old.json new.json
 {
   "module": "r.info",
-  "id": "r.info_1804289383",
+  "id": "r_info_4722a5e5637f47cb8bf561591f8a4435",
   "inputs": [
     {
       "param": "map",

@ninsbl
Copy link
Member Author

ninsbl commented Jun 5, 2024

Looking at the actual concept here, why this is actually needed? We already have the same JSON emitted from the tools themselves with --json

Valid question. My use case for that function is prototyping actinia workflows in jupyter.
Here, multiple modules can be combined in a dictionary, that then can be send as JSON to actinia. Note, that the functon also can add the export section for maps or stdout.

from grass.pygrass.modules.interface import Module
Module("r.info", map="elevation", run_=False).get_json_dict(stdout_export="table", stdout_delimiter="|", stdout_id="raster_info")

Overall, I think the get_json() function is more user-friendly, at least in the context of my usecase than the --json approach (though I considered that as well). It also alignes withh other similar functions in the modules interface, like get_bash()...

@wenzeslaus
Copy link
Member

Overall, I think the get_json() function is more user-friendly, at least in the context of my usecase than the --json approach (though I considered that as well).

Why you just don't call the tools with --json from get_json and add what you need there or in the library?

As far as the current state, you talk about interface and functionality, but I'm concerned with maintenance. If this would be merged, we would be left with maintenance of two JSON generators which are actinia-specific (so need to at least somewhat follow changes in actinia) and the JSON format is not well specified, at least not within GRASS GIS, further hindering the maintenance.

It also aligns with other similar functions in the modules interface, like get_bash()...

The Bash and Python functions don't duplicate any substantial code in the library. get_json does.

More generally, I was wondering if you even know about --json because using it or wrapping it would be an obvious solution, but it is undocumented and you did not mention it in the description.

@ninsbl
Copy link
Member Author

ninsbl commented Jun 7, 2024

I would not be disappointed if the decision is not to merge this. I can add that function to the Module object in my downstream code... No problem.

So please feel free to close this as wontfix, if that is preferable...

@wenzeslaus
Copy link
Member

Why don't you just call the tool with --json in the get_json_dict function?

Check other recent grass.pygrass PRs or issues. The overall issue there is that it tries to mimic what the actual command line parser is doing, but it fails for edge cases. Using the tool to figure out these cases would be a better solution, but it requires more substantial rewrite, so I was just doing smaller fixes here and there. Using --json would fit with this approach.

@wenzeslaus wenzeslaus modified the milestones: 8.4.0, 8.5.0 Jun 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request libraries Python Related code is in Python tests Related to Test Suite
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants