Skip to content

CI: Address Windows specific issues in testsuite - #2616

Open
ninsbl wants to merge 35 commits into
OSGeo:mainfrom
ninsbl:windows_testsuite
Open

ninsbl wants to merge 35 commits into
OSGeo:mainfrom
ninsbl:windows_testsuite

Conversation

@ninsbl

@ninsbl ninsbl commented Oct 28, 2022 •

Copy link
Copy Markdown
Member

Replaces: #1683


July 2026 AI analysis of what is possibly still relevant:

  • r.mfilter: the NamedTemporaryFile → gs.tempfile fix is a textbook Windows bug (can't reopen an open NamedTemporaryFile) and directly explains the 6 xfail'd tests there. r.mfilter: Avoid reopening NamedTemporaryFile on Windows in testsuite #7878
  • grassdb/test_manage.py: the os.sep-aware assertions map one-to-one onto the 4 xfail'd tests. grass.grassdb: Fix path separator expectations in manage tests on Windows #8050
  • test_parser_json.py: uses raw subprocess.Popen (not grass.script), so the shell= on win32 fix is still relevant; all 3 tests are xfail'd.
  • test_checkers.py / test_assertions.py: the newline="" fixes for MD5-checked files still apply, though test_assertions.py now writes via Path.write_text(), so the fix needs rewriting. grass.gunittest: Preserve exact bytes in MD5 test fixtures #8039
  • case.py: normalizing/stripping the reference string in assertLooksLike/assertModuleKeyValue (main only normalizes actual).
  • toolboxes.sh (python→python3) and v.edit/select_all_flag.sh (tr -d '\r'): both files are still on the exclusion list in .github/workflows/osgeo4w_gunittest.cfg, so the fixes are still applicable.

These would be better as individual PRs.

@ninsbl ninsbl added windows Microsoft Windows specific CI Continuous integration labels Oct 28, 2022
@ninsbl ninsbl added this to the 8.3.0 milestone Oct 28, 2022
@ninsbl

ninsbl commented Oct 31, 2022

Copy link
Copy Markdown
Member Author

With this PR success-rate of unit tests on MS Windows is up to 87% (from 80%), with 243 tests passing (almost as many as on Linux). There are a couple of tests left (e.g. i.maxlik or v.what tests), where I suspect that either tests (or assertions in the testsuite (e.g. with v.what) are not really cross platform. For the rest we may start looking at the module code to check if the test failure actually is a bug.
An example, where I here fixed the test, but test failure actually may be a bug is the v.in.lidar module. That module seems to behave differently on MS Windows and Linux with regards to projection handling and that may be actually a bug...

Anyway, I am happy about all sorts of feedback on this PR.

Comment on lines +6 to +7
python3 $GISBASE/gui/wxpython/core/toolboxes.py doctest
python3 $GISBASE/gui/wxpython/core/toolboxes.py test

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Do we have GRASS_PYTHON defined here or not? If yes, that might be the best choice, although I would prefer solution where plain python just works.

Comment thread gui/wxpython/core/toolboxes.py Outdated
Comment on lines +792 to +795
import __builtin__
if sys.version_info[0] == 2:
import __builtin__

__builtin__._ = new_translator
__builtin__._ = new_translator

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The "underscore" issue should still apply, so I would be surprised if doing it just for 2 is enough. Besides that, if there is 2-only code somewhere, it should be deleted. (But I think that's not the case here.)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Right. We do not support Python 2 anymore, so it is probably even better to remove Python 2 specific code to cleanup (also other places where Python 2 code pops up)?


# TODO: here we need a name of or path to the main GRASS GIS executable
executable = "grass"
executable = shutil.which("grass")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I would think only shutil.which or shell=True are needed for Windows, not both. I would prefer shutil.which or some equivalent of sys.executable in the grass package (e.g., grass.script.setup.executable).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I see. Unfortunately, both shutil.which and shell do not seem to help. Maybe better to switch to subprocess.run?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

subprocess.run is just an interface to Popen like all the others. I don't expect it would help. shutil.which needs grass to be on path to work which is likely not fulfilled.

This test is now unique - we don't have other tests which test the executable - we we may have more in the future or even write such code, so perhaps ignoring it now and adding grass.script.setup.executable later is the way to go.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This is one the of things for a separate PR. Getting the grass.script.setup.executable piece working would be nice to have. get_install_path is perhaps a good starting point (Python package path is known, path to installation is not). Lazy-loading seems appropriate, but there are still no properties for modules yet (?), but there is getattr.

Comment thread python/grass/gunittest/gmodules.py Outdated
# Make sure that universal newlines are returned
output = (
output.replace(os.linesep, "\n")
if os.linesep != "\n" and type(output) == str

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

type(output) is str?

@@ -1,4 +1,4 @@
from tempfile import NamedTemporaryFile
import grass.script as gscript

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

import grass.script as gs

def create_filter(self, options):
"""Create a temporary filter file with the given name and options."""
f = NamedTemporaryFile()
f = gscript.tempfile(create=False)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Returns string, the original is an IO object.

Comment on lines +124 to +125
# Prebuild C-modules for MS Windows are unlikely to run
# on fresh compiled GRASS GIS

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I thought this should fail at g.extension step already.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Addons are pre-build for MS Windows also for the development version:
https://wingrass.fsv.cvut.cz/grass83/addons/grass-8.3.dev/logs/
However, getting the addon-help fails because build versions differ...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh, I missed what test_github_install_official is. That makes sense. Mention the different build versions in the comment.

expected="10
10"
out=$(v.category option=print layer=2 input=vedit_test)
out=$(v.category option=print layer=2 input=vedit_test| tr -d '\r')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

BTW, skipping all .sh-based tests on Windows would be a fair solution I think.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I have no strong opinion here. MSYS has been dropped, so it is very unlikely that users will run shell scripts in real world cases. And I am not sure this is a real MS Windows test in that sense.
However, most of the shell tests work. So maybe it does not hurt to have them running for MS Windows as well...

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Okay, please add comment that the \r part is for Windows, so we know when to remove it.

However, I think the role of Bash/sh/... tests is to provide option for "quick and dirty" tests and for very specific cases, so supporting only Linux or unix is fine. Something to keep in mind.

Comment on lines -53 to +57
stdout, stderr = subprocess.Popen(args, stdout=subprocess.PIPE).communicate()
stdout, stderr = subprocess.Popen(
args, stdout=subprocess.PIPE, shell=sys.platform == "win32"
).communicate()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This would probably make more sense with direct support for this in grass.script, but to limit the solution only to here, would shutil.which work here at line 22?

expected="10
10"
out=$(v.category option=print layer=2 input=vedit_test)
out=$(v.category option=print layer=2 input=vedit_test| tr -d '\r')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Okay, please add comment that the \r part is for Windows, so we know when to remove it.

However, I think the role of Bash/sh/... tests is to provide option for "quick and dirty" tests and for very specific cases, so supporting only Linux or unix is fine. Something to keep in mind.

@echoix

echoix commented Mar 21, 2024

Copy link
Copy Markdown
Member

Do you still think this PR is the way forward? It has conflicts, but for instance the builtins import issue has need fixed in another PR in January, and there was a PR recently that changed a temporary file/NamedTemporaryFile, and it was the only usage in the code at the time.

@echoix

echoix commented Sep 21, 2024

Copy link
Copy Markdown
Member

I've skimmed through very quickly, and I think cutting out some line endings in the tests only for Windows is maybe not the right approach. It is something that we should probably fix for real instead, and to not care too much about io with Python, as it is handled way more transparently than on Python 2

@echoix echoix added the conflicts/needs rebase Rebase to or merge with the latest base branch is needed label Oct 22, 2025
@echoix

echoix commented Oct 22, 2025

Copy link
Copy Markdown
Member

Is there still something useful and relevant here that should be kept, 3 years later? Our testing situation is a bit better now, our Python code quality is way up since more than a year and a half, grass start up and initialization, especially for usage as a Python library is recently better, etc.

@petrasovaa

petrasovaa commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor

AI analysis of this PR, what is possibly still relevant:

  • r.mfilter: the NamedTemporaryFile → gs.tempfile fix is a textbook Windows bug (can't reopen an open NamedTemporaryFile) and directly explains the 6 xfail'd tests there.
  • grassdb/test_manage.py: the os.sep-aware assertions map one-to-one onto the 4 xfail'd tests.
  • test_parser_json.py: uses raw subprocess.Popen (not grass.script), so the shell= on win32 fix is still relevant; all 3 tests are xfail'd.
  • test_checkers.py / test_assertions.py: the newline="" fixes for MD5-checked files still apply, though test_assertions.py now writes via Path.write_text(), so the fix needs rewriting.
  • case.py: normalizing/stripping the reference string in assertLooksLike/assertModuleKeyValue (main only normalizes actual).
  • toolboxes.sh (python→python3) and v.edit/select_all_flag.sh (tr -d '\r'): both files are still on the exclusion list in .github/workflows/osgeo4w_gunittest.cfg, so the fixes are still applicable.

These would be better as individual PRs.

@ninsbl

ninsbl commented Jul 17, 2026

Copy link
Copy Markdown
Member Author

AI analysis of this PR, what is possibly still relevant:

We can keep the PR open for reference or open an issue, close this PR and point to the PR in the issue... Both is fine with me. I agree it should be implemented in separate, smaller PRs...

echoix added a commit to echoix/grass that referenced this pull request Sep 2, 2026
On Windows, a file opened via tempfile.NamedTemporaryFile() cannot be
reopened by another process while the Python handle is still open, so
r.mfilter failed to read the filter file created this way. Write the
filter contents to a path from grass.script.tempfile() instead, which
does not hold the file open, and drop the @xfail_windows markers this
fix should resolve.

Extracted and reworked as a standalone change from PR OSGeo#2616 (by Stefan
Blumentrath / @ninsbl), which combined this fix with many other
Windows-specific testsuite changes and has been open, unrebased, since
2022. Re-derived against current main rather than cherry-picked,
because @ninsbl's branch predates unrelated fixes already merged to
this same test file (a docstring/variance correction and other
@xfail_windows additions), which a direct cherry-pick would have
clobbered.

This has not been verified on an actual Windows run; CI on this PR
should confirm whether the @xfail_windows markers can indeed be
removed. Analysis of PR OSGeo#2616 assisted by AI (Claude), including
identifying this as an easily isolated, self-contained candidate for
its own PR; verify before merging.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HjAoKyq8bFN7cnNaZkwtV6
echoix added a commit to echoix/grass that referenced this pull request Sep 2, 2026
On Windows, a file opened via tempfile.NamedTemporaryFile() cannot be
reopened by another process while the Python handle is still open, so
r.mfilter failed to read the filter file created this way. Write the
filter contents to a path from grass.script.tempfile() instead, which
does not hold the file open, and drop the @xfail_windows markers this
fix should resolve.

Extracted and reworked as a standalone change from PR OSGeo#2616 (by Stefan
Blumentrath / @ninsbl), which combined this fix with many other
Windows-specific testsuite changes and has been open, unrebased, since
2022. Re-derived against current main rather than cherry-picked,
because @ninsbl's branch predates unrelated fixes already merged to
this same test file (a docstring/variance correction and other
@xfail_windows additions), which a direct cherry-pick would have
clobbered.

This has not been verified on an actual Windows run; CI on this PR
should confirm whether the @xfail_windows markers can indeed be
removed. Analysis of PR OSGeo#2616 assisted by AI (Claude), including
identifying this as an easily isolated, self-contained candidate for
its own PR; verify before merging.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
echoix added a commit to echoix/grass that referenced this pull request Oct 9, 2026
Python's default text-mode writing translates "\n" to os.linesep, which
on Windows turns the MD5 test fixtures into "\r\n" files. Two tests hash
them in binary mode against MD5 sums computed from "\n" content:
test_text_file_binary in test_checkers.py and test_assertFileMd5 in
test_assertions.py.

Write these fixtures with newline="" so the bytes match the hardcoded
sums on every platform. Do the same for the other fixtures written next
to file_with_md5, since test_assertFilesEqualMd5 compares their hashes
against it. Remove the now obsolete @xfail_windows markers from the two
tests, because an unexpected success makes the gunittest run fail.

Also fix the "platfrom" typos in the test_text_file_platform test name
and the platform_newline attribute.

Based on the newline handling in OSGeo#2616 by Stefan Blumentrath,
reworked against current main with AI assistance.

Co-authored-by: Stefan Blumentrath <4246620+ninsbl@users.noreply.github.com>
echoix added a commit that referenced this pull request Oct 9, 2026
Python's default text-mode writing translates "\n" to os.linesep, which
on Windows turns the MD5 test fixtures into "\r\n" files. Two tests hash
them in binary mode against MD5 sums computed from "\n" content:
test_text_file_binary in test_checkers.py and test_assertFileMd5 in
test_assertions.py.

Write these fixtures with newline="" so the bytes match the hardcoded
sums on every platform. Do the same for the other fixtures written next
to file_with_md5, since test_assertFilesEqualMd5 compares their hashes
against it. Remove the now obsolete @xfail_windows markers from the two
tests, because an unexpected success makes the gunittest run fail.

Also fix the "platfrom" typos in the test_text_file_platform test name
and the platform_newline attribute.

Based on the newline handling in #2616 by Stefan Blumentrath,
reworked against current main with AI assistance.

Co-authored-by: Stefan Blumentrath <4246620+ninsbl@users.noreply.github.com>
echoix pushed a commit to echoix/grass that referenced this pull request Oct 11, 2026
…dows

pathlib uses os.sep in the string form of paths, so the tests that
compare against forward-slash strings failed on Windows. Compare against
the same strings with os.sep and drop the xfail_windows markers from the
four tests which this fixes.

Extracted from OSGeo#2616 by Stefan Blumentrath.
echoix pushed a commit to echoix/grass that referenced this pull request Oct 11, 2026
…dows

pathlib uses os.sep in the string form of paths, so the tests that
compare against forward-slash strings failed on Windows. Compare against
the same strings with os.sep and drop the xfail_windows markers from the
four tests which this fixes.

Extracted from OSGeo#2616 by Stefan Blumentrath.
echoix pushed a commit to echoix/grass that referenced this pull request Oct 11, 2026
…dows

pathlib uses os.sep in the string form of paths, so the tests that
compare against forward-slash strings failed on Windows. Compare against
the same strings with os.sep and drop the xfail_windows markers from the
four tests which this fixes.

Extracted from OSGeo#2616 by Stefan Blumentrath.
echoix added a commit that referenced this pull request Oct 11, 2026
…dows (#8050)

pathlib uses os.sep in the string form of paths, so the tests that
compare against forward-slash strings failed on Windows. Compare against
the same strings with os.sep and drop the xfail_windows markers from the
four tests which this fixes.

Extracted from #2616 by Stefan Blumentrath.

Co-authored-by: Stefan Blumentrath <stefan.blumentrath@gmx.de>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI Continuous integration conflicts/needs rebase Rebase to or merge with the latest base branch is needed windows Microsoft Windows specific

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants