Skip to content

Conversation

HuidaeCho
Copy link
Member

This PR

  • renames grass.py to grass<VERSION>.py to avoid
Traceback (most recent call last):
  File "C:\Users\hcho\usr\grass\grass\build\output\bin\grass.py", line 2473, in <module>
    main()
    ~~~~^^
  File "C:\Users\hcho\usr\grass\grass\build\output\bin\grass.py", line 2120, in main
    from grass.app.runtime import RuntimePaths
ModuleNotFoundError: No module named 'grass.app'; 'grass' is not a package
  • generates grass.bat from lib/init/grass.bat.in, and
  • adds scripts to PATH for batch files.

@github-actions github-actions bot added Python Related code is in Python libraries CMake labels Sep 20, 2025
@nilason
Copy link
Contributor

nilason commented Sep 22, 2025

Would prepending GRASS_PYDIR to sys.path:

sys.path.append(GRASS_PYDIR)

be an alternative to versioning the file name?

@wenzeslaus
Copy link
Member

Hm, regardless, we should prepend. I'll adjust my PR.

We could also import in more low level way to avoid the version.

@HuidaeCho
Copy link
Member Author

Would prepending GRASS_PYDIR to sys.path:

sys.path.append(GRASS_PYDIR)

be an alternative to versioning the file name?

No, it doesn't work. Still trying to self-import because the main script name is the same as the package name.

@HuidaeCho
Copy link
Member Author

HuidaeCho commented Sep 23, 2025

It's OK on UN*X because the main script is grass with a shebang (not supported on Windows). If you rename grass to grass.py even on UN*X, you'll see this same issue.

@nilason
Copy link
Contributor

nilason commented Sep 23, 2025

Would prepending GRASS_PYDIR to sys.path:

sys.path.append(GRASS_PYDIR)

be an alternative to versioning the file name?

No, it doesn't work. Still trying to self-import because the main script name is the same as the package name.

Oh, too bad. Not sure what to do, it is not ideal to re-add the version to the main executive.

@HuidaeCho
Copy link
Member Author

HuidaeCho commented Sep 23, 2025

Would prepending GRASS_PYDIR to sys.path:

sys.path.append(GRASS_PYDIR)

be an alternative to versioning the file name?

No, it doesn't work. Still trying to self-import because the main script name is the same as the package name.

Oh, too bad. Not sure what to do, it is not ideal to re-add the version to the main executive.

This PR doesn't change anything for UN*X. grass is still the main executable on UN*X, but grass.bat is the main executable on Windows because we cannot directly run grass (renamed from grass.py) with no shebang support.

@nilason
Copy link
Contributor

nilason commented Sep 23, 2025

Oh, too bad. Not sure what to do, it is not ideal to re-add the version to the main executive.

This PR doesn't change anything for UNX. grass is still the main executable on UNX, but grass.bat is the main executable on Windows because we cannot directly run grass (renamed from grass.py) with no shebang support.

I understand it is only for Win. If you will do scripting on Win, wouldn't grass.py be the main executive?

@HuidaeCho
Copy link
Member Author

Oh, too bad. Not sure what to do, it is not ideal to re-add the version to the main executive.

This PR doesn't change anything for UN_X. grass is still the main executable on UN_X, but grass.bat is the main executable on Windows because we cannot directly run grass (renamed from grass.py) with no shebang support.

I understand it is only for Win. If you will do scripting on Win, wouldn't grass.py be the main executive?

For Python scripting, yes grass.py is the main entry point. We just cannot name it grass.py on Windows. It doesn't have to have a version number. It can be grass_main.py.

@wenzeslaus
Copy link
Member

If I understand correctly, the situation now is:

  • unix: grass representing grass.py
  • windows: grass.bat pointing to grass85.py

This looks platform-appropriate to me.

Anyway, I made the change with prepend in #6393.

In my local test on Linux, it seems that insert(0, helps, assuming you didn't try to import it beforehand, which #6393 purposefully does.

PYTHONPATH=.../dist.x86_64-pc-linux-gnu/etc/python python
Python 3.12.3 (main, Aug 14 2025, 17:47:21) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.path
['', '.../dist.x86_64-pc-linux-gnu/etc/python', '/usr/lib/python312.zip', '/usr/lib/python3.12', '/usr/lib/python3.12/lib-dynload', '/usr/local/lib/python3.12/dist-packages', '/usr/lib/python3/dist-packages']
>>> sys.path.insert(0, ".../dist.x86_64-pc-linux-gnu/etc/python")
>>> sys.path
['.../dist.x86_64-pc-linux-gnu/etc/python', '', '.../dist.x86_64-pc-linux-gnu/etc/python', '/usr/lib/python312.zip', '/usr/lib/python3.12', '/usr/lib/python3.12/lib-dynload', '/usr/local/lib/python3.12/dist-packages', '/usr/lib/python3/dist-packages']
>>> import grass.script

PYTHONPATH goes only after '' but insert(0, works as expected.

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.

I would be for merging the versioned part of this PR right now. If we want to make it better in the future, we can refine #6393, use importlib, or the __main__.py file Python mechanics.

The scripts part is not clear to me. With Autotools we don't have separate scripts on Linux, but we may have them for Windows. I don't know what is the exact reasoning behind that. It is clear that Linux just treats all the executables the same, while more care is needed to run a Python script on Windows.

Comment on lines -134 to +138
else:
# Without FHS, scripts are separated like in the source code.
path = os.path.join(install_path, "scripts")
if os.path.exists(path):
paths.appendleft(path)

# Without FHS, scripts are separated like in the source code.
path = os.path.join(install_path, "scripts")
if os.path.exists(path):
paths.appendleft(path)
Copy link
Member

Choose a reason for hiding this comment

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

Confusing, I would say the original code was wrong for Windows with Autotools because it would skip it. Both the old code and new code should be fine for Linux because there should be no scripts directory AFAIK, but then the comment is misleading. I didn't look at blame - if I'm the author, I would be twice as confused as I'm now. :-)

In any case, testing os.path.exists(path) is good, but skipping based on the platform is even better if we already have that info.

Comment on lines 13 to +16
# START_UP is the variable used in grass.py, grass.sh.in and grass.bat.in
set(START_UP ${PROJECT_NAME_LOWER})
if(WIN32)
set(START_UP "${START_UP}.py")
set(START_UP "${START_UP}${GRASS_VERSION_NUMBER}.py")
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 appreciate a comment in the source code providing the reason. Something like "Python file has version to avoid issues with import grass statements". It could also be called grass_main.py instead of using the version if that would simplify things or help clarity.

@wenzeslaus
Copy link
Member

I made even further changes to #6393 and it works for me on Linux with grass.py. I would give it a try before merging the version piece here. We may still want to avoid the failed import with the "versioned" file, but we don't have to, because that's handled gracefully with #6393. #6393 needs a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CMake libraries Python Related code is in Python
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants