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

Open and load --code file and --py-args arguments in C++ #60134

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

btzy
Copy link
Contributor

@btzy btzy commented Jan 13, 2025

Description

I took a stab at #60120 to see if we can design a better alternative to #60121.

Instead of doing string substitution into Python code, we use the proper Python C API functions to assign to sys.argv and execute a Python script from a file. This avoids the issues that arise due to improper escaping of strings (e.g. ' and \). Unix file names in particular may contain any non-null character (including non-printable characters), and trying to escape such characters manually would otherwise be difficult to get right. String substitution is also possibly vulnerable to code injection attacks, as it is possible to carefully craft a string containing code that will be executed.

There was a hack that converts Windows-style directory separators to Unix-style directory separators. This is no longer necessary, and therefore has been removed.

Fixes #60120.

@domi4484
Copy link
Contributor

@btzy when we introduced --py-args we decided on purpose to make the args available for each python execution in QGIS independently from the --code argument.
But I can't remember exactly what's the use case thought, maybe @m-kuhn do you remember more?

@btzy If you need arguments valid only in the context of the --code script I would suggest to add a new parameter --code-args. But then arise the question what to do if they are both set?

@m-kuhn
Copy link
Member

m-kuhn commented Jan 16, 2025

No strong opinion. What would be the reason to not make it also available for other python code than --code?

@btzy
Copy link
Contributor Author

btzy commented Jan 17, 2025

@domi4484 I misunderstood the help string of --py-args. I'll modify this PR. Likely we'll need another function in QgsPythonUtils to set the sys.argv variable (separate from runFile).

@btzy btzy marked this pull request as ready for review January 18, 2025 15:54
@btzy
Copy link
Contributor Author

btzy commented Jan 18, 2025

I'm not sure how to trigger the automatic Windows build that other PRs have; can someone help me get the GitHub Action to run?

@btzy
Copy link
Contributor Author

btzy commented Jan 18, 2025

Separately, I made #60183 to fix the grammar error in the help, which was what originally misled me to think that --py-args is only used with --code.

@btzy btzy force-pushed the codearg branch 4 times, most recently from ef2a7f6 to 20e2318 Compare January 19, 2025 13:10
Copy link

github-actions bot commented Jan 19, 2025

🪟 Windows builds

Download Windows builds of this PR for testing.
Debug symbols for this build are available here.
(Built from commit 3e1671a)

🪟 Windows Qt6 builds

Download Windows Qt6 builds of this PR for testing.
(Built from commit 3e1671a)

@btzy btzy force-pushed the codearg branch 6 times, most recently from 64c5dda to 1f44ac4 Compare January 22, 2025 15:34
@btzy
Copy link
Contributor Author

btzy commented Jan 23, 2025

I've tested that the Windows build works:

  • Passing --code runs the Python code
  • Passing --code with --py-args make the extra args available in the Python code in sys.argv
  • Passing --py-args, and then later opening the Python console and running sys.argv shows the arguments

@btzy btzy changed the title Open and load --code file and arguments in C++ Open and load --code file and --py-args arguments in C++ Jan 25, 2025
@btzy
Copy link
Contributor Author

btzy commented Jan 28, 2025

@m-kuhn Can I get a review for this?

Copy link

The QGIS project highly values your contribution and would love to see this work merged! Unfortunately this PR has not had any activity in the last 14 days and is being automatically marked as "stale". If you think this pull request should be merged, please check

  • that all unit tests are passing

  • that all comments by reviewers have been addressed

  • that there is enough information for reviewers, in particular

    • link to any issues which this pull request fixes

    • add a description of workflows which this pull request fixes

    • add screenshots if applicable

  • that you have written unit tests where possible
    In case you should have any uncertainty, please leave a comment and we will be happy to help you proceed with this pull request.
    If there is no further activity on this pull request, it will be closed in a week.

@github-actions github-actions bot added the stale Uh oh! Seems this work is abandoned, and the PR is about to close. label Feb 12, 2025
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) )
{
ret = "Cannot open file";
goto error;
Copy link
Member

Choose a reason for hiding this comment

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

Please avoid goto

if ( !argsobj )
{
ret = "Error occurred in PyList_New";
goto error;
Copy link
Member

Choose a reason for hiding this comment

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

Same

ret = QString( "SetArgvTraceback" ) + getTraceback();
else
ret = "Error occurred in PyImport_ImportModule";
goto error;
Copy link
Member

Choose a reason for hiding this comment

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

Same

Copy link
Contributor Author

Choose a reason for hiding this comment

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

How would you like me to rewrite this code? We need to execute the cleanup code at the end whether or not this function succeeds.

The most C++-ic way to do this is to write an RAII wrapper class around PyGILState_Ensure/PyGILState_Release and PyObject/Py_XDECREF. Or for a more ad-hoc mechanism, I might have used the equivalent of std::experimental::scope_exit] (both Folly and Abseil have this in some form, but QGIS uses neither of them). I would have written code in one of the above two ways if this was for my own project, but I do not see existing code in QGIS that leverages either of them.

If the above solutions are unacceptable, we would have to either invert the guard clauses into nested if-statements, which is generally considered to be bad practice. We are thus left with goto statements, which seem to be an idiom for writing cleanup code in C.

What would be most appropriate for the QGIS codebase? Writing my own scope guard?

@m-kuhn
Copy link
Member

m-kuhn commented Feb 12, 2025

Thanks, using sys.argv does look like the correct approach!

@github-actions github-actions bot removed the stale Uh oh! Seems this work is abandoned, and the PR is about to close. label Feb 12, 2025
@nyalldawson nyalldawson added Frozen Feature freeze - Do not merge! and removed Frozen Feature freeze - Do not merge! labels Feb 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Windows: --code flag cannot accept paths with single quote (')
4 participants