grass
grass copied to clipboard
grass.jupyter: Add Query Button to InteractiveMap
For some reason, I can't see any results for a vector map. Also, it behaves strangely, when I click first time, it works (for raster) and then when I click second time on the map, the output disappears. Does it behave the same for you?
It behaves like this:
https://github.com/OSGeo/grass/assets/77328768/cab17ac2-e656-4e78-b6ab-4e1b679a4efc
For some reason, I can't see any results for a vector map. Also, it behaves strangely, when I click first time, it works (for raster) and then when I click second time on the map, the output disappears. Does it behave the same for you?
It behaves like this:
Even there you can see strange flashing around 13th second.
I found out why I don't see any vector results, you don't set the threshold. vector_what has a distance parameter, but it needs to change based on the extent of the leaflet map, similarly like it is done in GUI:
https://github.com/OSGeo/grass/blob/main/gui/wxpython/mapdisp/frame.py#L1040
The main problem here is still the graphical representation of the results, it doesn't look very well. The css would have to be tweaked to make the table look nicer. @29riyasaxena Do you agree? Is that something you want to work on as part of this PR? Or we could leave that as separate PR.
The main problem here is still the graphical representation of the results, it doesn't look very well. The css would have to be tweaked to make the table look nicer. @29riyasaxena Do you agree? Is that something you want to work on as part of this PR? Or we could leave that as separate PR.
I think I can do this since it is not a difficult task. Also, I couldn't find the tests of InteractiveMap.
I think I can do this since it is not a difficult task. Also, I couldn't find the tests of
InteractiveMap.
https://github.com/OSGeo/grass/blob/main/python/grass/jupyter/testsuite/interactivemap_test.py
I think I can do this since it is not a difficult task. Also, I couldn't find the tests of
InteractiveMap.https://github.com/OSGeo/grass/blob/main/python/grass/jupyter/testsuite/interactivemap_test.py
Hi Anna, Thank you for providing the link. Running tests give me the following error:
=========================================================== short test summary info ============================================================ FAILED interactivemap_test.py::test - SystemExit: True ERROR interactivemap_test.py::TestDisplay::test_basic - TypeError: can only concatenate str (not "NoneType") to str ERROR interactivemap_test.py::TestDisplay::test_save_as_html - TypeError: can only concatenate str (not "NoneType") to str
Could you please check what's going wrong here?
Could you please check what's going wrong here?
It runs for me with this PR. How do you run the test? Is there any more output?
Could you please check what's going wrong here?
It runs for me with this PR. How do you run the test? Is there any more output?
Here's the complete output:
============================= test session starts ==============================
platform linux -- Python 3.10.12, pytest-8.1.0, pluggy-1.4.0
rootdir: /home/riya/grass
configfile: pyproject.toml
plugins: cov-4.1.0, hypothesis-6.100.1, anyio-4.3.0
collected 3 items
interactivemap_test.py FEE [100%]
==================================== ERRORS ====================================
___________________ ERROR at setup of TestDisplay.test_basic ___________________
cls = <class 'interactivemap_test.TestDisplay'>, module = Module('g.region')
expecting_stdout = False, kwargs = {'raster': 'elevation'}
errors = 'ERROR: Raster map <elevation> not found\n\nSee available raster maps:\n'
re = <module 're' from '/usr/lib/python3.10/re.py'>
@classmethod
def runModule(cls, module, expecting_stdout=False, **kwargs):
"""Run PyGRASS module.
Runs the module and raises an exception if the module ends with
non-zero return code. Usually, this is the same as testing the
return code and raising exception but by using this method,
you give testing framework more control over the execution,
error handling and storing of output.
In terms of testing framework, this function causes a common error,
not a test failure.
:raises CalledModuleError: if the module failed
"""
module = _module_from_parameters(module, **kwargs)
_check_module_run_parameters(module)
try:
> module.run()
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/gunittest/case.py:1319:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/pygrass/modules/interface/module.py:838: in run
self.wait()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Module('g.region')
def wait(self):
"""Wait for the module to finish. Call this method if
the run() call was performed with self.false_ = False.
:return: A reference to this object
"""
if self._finished is False:
if self.stdin:
self.stdin = encode(self.stdin)
stdout, stderr = self._popen.communicate(input=self.stdin)
self.outputs["stdout"].value = decode(stdout) if stdout else ""
self.outputs["stderr"].value = decode(stderr) if stderr else ""
self.time = time.time() - self.start_time
self.returncode = self._popen.returncode
self._finished = True
if self._popen.poll():
> raise CalledModuleError(
returncode=self._popen.returncode,
code=self.get_bash(),
module=self.name,
errors=stderr,
)
E grass.exceptions.CalledModuleError: Module run `g.region raster=elevation` ended with an error.
E The subprocess ended with a non-zero return code: 1. See the following errors:
E b'ERROR: Raster map <elevation> not found\n'
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/pygrass/modules/interface/module.py:859: CalledModuleError
During handling of the above exception, another exception occurred:
cls = <class 'interactivemap_test.TestDisplay'>
@classmethod
def setUpClass(cls):
"""Ensures expected computational region"""
# to not override mapset's region (which might be used by other tests)
cls.use_temp_region()
# cls.runModule or self.runModule is used for general module calls
# we'll use the elevation raster as a test display
> cls.runModule("g.region", raster="elevation")
interactivemap_test.py:60:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cls = <class 'interactivemap_test.TestDisplay'>, module = Module('g.region')
expecting_stdout = False, kwargs = {'raster': 'elevation'}
errors = 'ERROR: Raster map <elevation> not found\n\nSee available raster maps:\n'
re = <module 're' from '/usr/lib/python3.10/re.py'>
@classmethod
def runModule(cls, module, expecting_stdout=False, **kwargs):
"""Run PyGRASS module.
Runs the module and raises an exception if the module ends with
non-zero return code. Usually, this is the same as testing the
return code and raising exception but by using this method,
you give testing framework more control over the execution,
error handling and storing of output.
In terms of testing framework, this function causes a common error,
not a test failure.
:raises CalledModuleError: if the module failed
"""
module = _module_from_parameters(module, **kwargs)
_check_module_run_parameters(module)
try:
module.run()
except CalledModuleError:
# here exception raised by run() with finish_=True would be
# almost enough but we want some additional info to be included
# in the test report
errors = module.outputs.stderr
# provide diagnostic at least in English locale
# TODO: standardized error code would be handy here
import re
if re.search("Raster map.*not found", errors, flags=re.DOTALL):
errors += "\nSee available raster maps:\n"
> errors += call_module("g.list", type="raster")
E TypeError: can only concatenate str (not "NoneType") to str
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/gunittest/case.py:1331: TypeError
_______________ ERROR at setup of TestDisplay.test_save_as_html ________________
cls = <class 'interactivemap_test.TestDisplay'>, module = Module('g.region')
expecting_stdout = False, kwargs = {'raster': 'elevation'}
errors = 'ERROR: Raster map <elevation> not found\n\nSee available raster maps:\n'
re = <module 're' from '/usr/lib/python3.10/re.py'>
@classmethod
def runModule(cls, module, expecting_stdout=False, **kwargs):
"""Run PyGRASS module.
Runs the module and raises an exception if the module ends with
non-zero return code. Usually, this is the same as testing the
return code and raising exception but by using this method,
you give testing framework more control over the execution,
error handling and storing of output.
In terms of testing framework, this function causes a common error,
not a test failure.
:raises CalledModuleError: if the module failed
"""
module = _module_from_parameters(module, **kwargs)
_check_module_run_parameters(module)
try:
> module.run()
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/gunittest/case.py:1319:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/pygrass/modules/interface/module.py:838: in run
self.wait()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = Module('g.region')
def wait(self):
"""Wait for the module to finish. Call this method if
the run() call was performed with self.false_ = False.
:return: A reference to this object
"""
if self._finished is False:
if self.stdin:
self.stdin = encode(self.stdin)
stdout, stderr = self._popen.communicate(input=self.stdin)
self.outputs["stdout"].value = decode(stdout) if stdout else ""
self.outputs["stderr"].value = decode(stderr) if stderr else ""
self.time = time.time() - self.start_time
self.returncode = self._popen.returncode
self._finished = True
if self._popen.poll():
> raise CalledModuleError(
returncode=self._popen.returncode,
code=self.get_bash(),
module=self.name,
errors=stderr,
)
E grass.exceptions.CalledModuleError: Module run `g.region raster=elevation` ended with an error.
E The subprocess ended with a non-zero return code: 1. See the following errors:
E b'ERROR: Raster map <elevation> not found\n'
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/pygrass/modules/interface/module.py:859: CalledModuleError
During handling of the above exception, another exception occurred:
cls = <class 'interactivemap_test.TestDisplay'>
@classmethod
def setUpClass(cls):
"""Ensures expected computational region"""
# to not override mapset's region (which might be used by other tests)
cls.use_temp_region()
# cls.runModule or self.runModule is used for general module calls
# we'll use the elevation raster as a test display
> cls.runModule("g.region", raster="elevation")
interactivemap_test.py:60:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
cls = <class 'interactivemap_test.TestDisplay'>, module = Module('g.region')
expecting_stdout = False, kwargs = {'raster': 'elevation'}
errors = 'ERROR: Raster map <elevation> not found\n\nSee available raster maps:\n'
re = <module 're' from '/usr/lib/python3.10/re.py'>
@classmethod
def runModule(cls, module, expecting_stdout=False, **kwargs):
"""Run PyGRASS module.
Runs the module and raises an exception if the module ends with
non-zero return code. Usually, this is the same as testing the
return code and raising exception but by using this method,
you give testing framework more control over the execution,
error handling and storing of output.
In terms of testing framework, this function causes a common error,
not a test failure.
:raises CalledModuleError: if the module failed
"""
module = _module_from_parameters(module, **kwargs)
_check_module_run_parameters(module)
try:
module.run()
except CalledModuleError:
# here exception raised by run() with finish_=True would be
# almost enough but we want some additional info to be included
# in the test report
errors = module.outputs.stderr
# provide diagnostic at least in English locale
# TODO: standardized error code would be handy here
import re
if re.search("Raster map.*not found", errors, flags=re.DOTALL):
errors += "\nSee available raster maps:\n"
> errors += call_module("g.list", type="raster")
E TypeError: can only concatenate str (not "NoneType") to str
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/gunittest/case.py:1331: TypeError
=================================== FAILURES ===================================
_____________________________________ test _____________________________________
def test():
"""Run a test of a module."""
# TODO: put the link to to the report only if available
# TODO: how to disable Python code coverage for module and C tests?
# TODO: we probably need to have different test functions for C, Python modules,
# and Python code
# TODO: combine the results using python -m coverage --help | grep combine
# TODO: function to anonymize/beautify file names (in content and actual filenames)
# TODO: implement coverage but only when requested by invoker and only if
# it makes sense for tests (need to know what is tested)
# doing_coverage = False
# try:
# import coverage
# doing_coverage = True
# cov = coverage.coverage(omit="*testsuite*")
# cov.start()
# except ImportError:
# pass
# TODO: add some message somewhere
# TODO: enable passing omit to exclude also gunittest or nothing
program = GrassTestProgram(
module="__main__", exit_at_end=False, grass_location="all"
)
# TODO: check if we are in the directory where the test file is
# this will ensure that data directory is available when it is requested
# if doing_coverage:
# cov.stop()
# cov.html_report(directory='testcodecoverage')
# TODO: is sys.exit the right thing here
> sys.exit(not program.result.wasSuccessful())
E SystemExit: True
/mnt/c/Users/29riy/Documents/projects/grass/dist.x86_64-pc-linux-gnu/etc/python/grass/gunittest/main.py:113: SystemExit
----------------------------- Captured stderr call -----------------------------
E
======================================================================
ERROR: interactivemap_test (unittest.loader._FailedTest)
----------------------------------------------------------------------
AttributeError: module '__main__' has no attribute 'interactivemap_test'
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
=============================== warnings summary ===============================
../../../../../.local/lib/python3.10/site-packages/_pytest/config/__init__.py:1437
/home/riya/.local/lib/python3.10/site-packages/_pytest/config/__init__.py:1437: PytestConfigWarning: Unknown config option: timeout
self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED interactivemap_test.py::test - SystemExit: True
ERROR interactivemap_test.py::TestDisplay::test_basic - TypeError: can only c...
ERROR interactivemap_test.py::TestDisplay::test_save_as_html - TypeError: can...
==================== 1 failed, 1 warning, 2 errors in 3.20s ====================
Is it because of wrong PYTHONPATH?
I am working in ~/grass.
pip install pytest-timeout
It's saying Raster map elevation not found, you need to run it in with e.g. the nc_basic_spm_grass7 dataset.
Running tests like this: grass /home/riya/grass/data/grassdata/nc_basic_spm_grass7/user1 --exec python3 /home/riya/grass/python/grass/jupyter/testsuite/interactivemap_test.py worked for me.
Using CSS will make it easier to customize, please incorporate this CSS:
<style>
table {
border-collapse: collapse;
width: 100%;
font-size: 12px;
font-family: Arial, sans-serif;
}
th {
background-color: #666666;
color: white;
text-align: center;
font-size: 12px;
}
td {
padding-left: 3px;
padding-right: 3px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
tr:nth-child(odd) {
background-color: #ffffff;
}
td:last-child {
text-align: right;
}
</style>
Could you please try to address the code quality issues from the CI?
Could you please try to address the code quality issues from the CI?
It should also be with a merge from main into this branch, it is 189 commits behind, and LOTS have changed since, especially for Python
To clarify this PR for others, could you please edit the description of this PR and include a brief summary and a most recent screenshot?
Given #3838 is now merged, we need to make sure these modes (query, region) don't interact in a weird way. I think the toggle buttons should be exclusive, so when you toggle query button, the region button should untoggle (and hide region). There is ToggleButtons widget which does that, but probably more changes in the handling of both modes are needed.