GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — gh-127350: Add Py_fopen() function by vstinner · Pull Request #127821 · python/cpython

Conversation

@vstinner

@vstinner vstinner commented Dec 11, 2024 •
edited by github-actions Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Rename _Py_fopen_obj() to Py_fopen(). The function now also accepts bytes path on Windows.

Remove the private, undocumented, and untested function _Py_fopen_obj().

  • Issue: _Py_wfopen no longer exported #127350

📚 Documentation preview 📚: https://cpython-previews--127821.org.readthedocs.build/

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@vstinner
pythongh-127350: Add Py_fopen() function
773c4d9
Rename _Py_fopen_obj() to Py_fopen(). The function now also accepts
bytes path on Windows.

Remove the private, undocumented, and untested function
_Py_fopen_obj().
@vstinner
vstinner requested review from ericsnowcurrently and kumaraditya303 as code owners December 11, 2024 12:27
@bedevere-app bedevere-app Bot mentioned this pull request Dec 11, 2024
_Py_wfopen no longer exported #127350
Closed
@bedevere-app bedevere-app Bot added the awaiting core review label Dec 11, 2024
@zooba

zooba commented Dec 11, 2024

Copy link
Copy Markdown
Member

Do we need Py_fclose as well?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

rruuaanng
rruuaanng reviewed Dec 12, 2024
View reviewed changes
Comment thread Modules/_ssl.c Resolved

Uh oh!

There was an error while loading. Please reload this page.

@rruuaanng

rruuaanng commented Dec 12, 2024

Copy link
Copy Markdown
Contributor

Do we need Py_fclose as well?

fclose seems to be enough, we don't need to wrap it(Unless we use CloseHandle to close the file).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Dec 12, 2024

Copy link
Copy Markdown
Member Author

@zooba:

Do we need Py_fclose as well?

Py_fopen() adds values to fopen(): accept a Python object, make the file descriptor non-inheritable, raise an exception on error.

Py_fclose() would just call fclose() without any additional value? I would prefer to not add it unless we have to, and call directly fclose(). I asked the reporter if Py_fclose() would be needed.

To be honest, I don't understand well the Windows DLL issue. From what I understood, to use a FILE* in Python DLL, it should be open in the Python DLL. Otherwise, things can go wrong if the C library version is not exactly the same in two DLLs. But I don't know if it's safe to call fopen() / Py_fopen() in DLL A and call fclose() in DLL B.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@PlanetCNC

PlanetCNC commented Dec 12, 2024

Copy link
Copy Markdown

PyRun_AnyFileExFlags has "closeit" parameter which I always used.
But you are correct. Py_fopen() needs Py_fclose().

Thank you guys for doing all this.

asvetlov reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner

vstinner commented Dec 12, 2024

Copy link
Copy Markdown
Member Author

But you are correct. Py_fopen() needs Py_fclose().

Is Py_fclose() needed because of the DLL issue?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@zooba

zooba commented Dec 12, 2024

Copy link
Copy Markdown
Member

Is Py_fclose() needed because of the DLL issue?

Yes. When you call Py_fopen(), you will get a FILE * from whichever C runtime Python is linked to, which isn't necessarily the same as your own application. So you can only pass it back to the same C runtime - it must only be passed into Python APIs, essentially. So regular fclose might crash (or close a different file), and you need Py_fclose() to make sure it goes back to the right runtime.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
Add Py_fclose() function
b80f424
@vstinner

vstinner commented Dec 13, 2024

Copy link
Copy Markdown
Member Author

Ok, I wanted to make sure that I get the rationale correctly.

I added Py_fclose() function and documented that files opened by Py_fopen() must only be closed by Py_fclose().

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

vstinner added 2 commits December 13, 2024 14:37
@vstinner
Merge branch 'main' into py_fopen
14fb249
@vstinner
Replace _Py_fopen_obj() with Py_fopen() in sysmodule.c
7390c5e
@zooba

zooba commented Dec 13, 2024

Copy link
Copy Markdown
Member

Your updated documentation seems a bit snarky. The Py_fclose may be needed on any platform depending on your static linking situation.

I see no reason not to just document it as "should be used to close files opened by Py_fopen" and if people manage to use fclose and it works then good for them.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
Simplify Py_fclose() documentation
26a5a56
@vstinner

vstinner commented Dec 13, 2024

Copy link
Copy Markdown
Member Author

Your updated documentation seems a bit snarky. The Py_fclose may be needed on any platform depending on your static linking situation.

It's not my intent to be snarky. I just tried to explain why calling fclose() directly can cause issues in practice.

I see no reason not to just document it as "should be used to close files opened by Py_fopen" and if people manage to use fclose and it works then good for them.

Ok, let's do that.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
Run make clinic
4375566
zooba
zooba reviewed Dec 13, 2024
View reviewed changes
Comment thread Doc/c-api/sys.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@vstinner @zooba
Update Doc/c-api/sys.rst
a779321
Co-authored-by: Steve Dower <[email protected]>
zooba
zooba approved these changes Dec 16, 2024
View reviewed changes
@bedevere-app bedevere-app Bot added awaiting merge and removed awaiting core review labels Dec 16, 2024
@vstinner
Document Py_fclose() return value
e613374
@vstinner vstinner mentioned this pull request Dec 16, 2024
Add public Py_fopen() and Py_fclose() functions, and remove private _Py_fopen_obj() function capi-workgroup/decisions#51
Closed
10 of 12 tasks
@vstinner

vstinner commented Dec 16, 2024

Copy link
Copy Markdown
Member Author

I created capi-workgroup/decisions#51: "Add public Py_fopen() and Py_fclose() functions, and remove private _Py_fopen_obj() function".

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@serhiy-storchaka
serhiy-storchaka self-requested a review December 31, 2024 15:16
serhiy-storchaka
serhiy-storchaka approved these changes Dec 31, 2024
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

LGTM in general. I would like to see more tests. The support of the path-like protocol is inconsistent.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Python/fileutils.c Outdated
wmode, Py_ARRAY_LENGTH(wmode));
if (usize == 0) {
PyErr_SetFromWindowsErr(0);
wchar_t wmode[10];

@serhiy-storchaka serhiy-storchaka Dec 31, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

TODO: Add tests for mode: NULL, non-decodable (non-ASCII) mode, too long mode (e.g. "rt+, ccs=UTF-8").

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@vstinner vstinner Jan 6, 2025

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

I added a test for "too long mode" and non-ASCII mode.

Passing NULL does crash. I don't know how to modify the Argument Clinic code to accept NULL.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@serhiy-storchaka serhiy-storchaka Jan 6, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

You can use "z#" to pass arbitrary sequence of bytes or NULL. In Argument Clinic it is expressed as str(zeroes=True, accept={robuffer, str, NoneType}).

Use the NULLABLE macro for path.

If it crashes, just add a comment # CRASHES with specific call as in other tests as indication that we did not miss such case, but cannot test it.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@vstinner vstinner Jan 6, 2025

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

If it crashes, just add a comment # CRASHES with specific call as in other tests as indication that we did not miss such case, but cannot test it.

Ok, I added a comment.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread Lib/test/test_capi/test_file.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/c-api/sys.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/c-api/sys.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

@kumaraditya303
kumaraditya303 removed their request for review January 3, 2025 10:17
erlend-aasland
erlend-aasland reviewed Jan 4, 2025
View reviewed changes
Comment thread Doc/c-api/sys.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Doc/c-api/sys.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

erlend-aasland
erlend-aasland reviewed Jan 4, 2025
View reviewed changes
Comment thread Doc/c-api/sys.rst Resolved

Uh oh!

There was an error while loading. Please reload this page.

vstinner added 9 commits January 6, 2025 11:30
@vstinner
Merge branch 'main' into py_fopen
a908b72
@vstinner
Address some of Serhiy's review
2af4d2b
@vstinner
Address Erlend's review
8e9170e
@vstinner
Add more tests
a8c26b2
@vstinner
Support __fspath__() protocol on Windows
5b52a4e
Test also non-ASCII mode.
@vstinner
Update doc for path-like object
e6a53fe
@vstinner
Keep _Py_fopen_obj() function
1d1e7f4
@vstinner
Fix typo
335c1bc
@vstinner
Fix test on macOS and WASI
8241422
* Skip TESTFN_UNENCODABLE if it's None.
* Remove TESTFN_UNDECODABLE test.
@vstinner
vstinner enabled auto-merge (squash) January 6, 2025 11:37
@vstinner
vstinner disabled auto-merge January 6, 2025 11:37
@vstinner
vstinner enabled auto-merge (squash) January 6, 2025 11:38
erlend-aasland
erlend-aasland approved these changes Jan 6, 2025
View reviewed changes
serhiy-storchaka
serhiy-storchaka reviewed Jan 6, 2025
View reviewed changes
Comment thread Lib/test/test_capi/test_file.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_capi/test_file.py Resolved

Uh oh!

There was an error while loading. Please reload this page.

Comment thread Lib/test/test_capi/test_file.py

# non-ASCII mode failing with "Invalid argument"
with self.assertRaises(OSError):
_testcapi.py_fopen(__file__, "\xe9")

@serhiy-storchaka serhiy-storchaka Jan 6, 2025 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

"\xe9" is encoded to b'\xc3\xa9'. Please test also with non-UTF-8 bytes. You may get different error on Windows. Actually, it may depend on the locale.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@vstinner vstinner Jan 6, 2025

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

It's not possible to pass non-UTF-8 bytes, PySys_Audit() decodes the mode from UTF-8 in strict mode:

    if (PySys_Audit("open", "Osi", path, mode, 0) < 0) {
        return NULL;
    }

I don't think that it's worth to "support" non-UTF-8 just for the test, whereas it's rejected anyway by fopen().

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
Comment thread Python/fileutils.c Outdated
wmode, Py_ARRAY_LENGTH(wmode));
if (usize == 0) {
PyErr_SetFromWindowsErr(0);
wchar_t wmode[10];

@serhiy-storchaka serhiy-storchaka Jan 6, 2025

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

You can use "z#" to pass arbitrary sequence of bytes or NULL. In Argument Clinic it is expressed as str(zeroes=True, accept={robuffer, str, NoneType}).

Use the NULLABLE macro for path.

If it crashes, just add a comment # CRASHES with specific call as in other tests as indication that we did not miss such case, but cannot test it.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
serhiy-storchaka
serhiy-storchaka reviewed Jan 6, 2025
View reviewed changes

@serhiy-storchaka serhiy-storchaka left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

Yet more test suggestions.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@vstinner
vstinner disabled auto-merge January 6, 2025 11:54
vstinner added 3 commits January 6, 2025 13:13
@vstinner
Rewrite the Windows implementation
c91aa82
@vstinner
Use FakePath
0fc6dc1
@vstinner
NULL mode does crash
dda4335
@vstinner
vstinner enabled auto-merge (squash) January 6, 2025 12:36
@vstinner

vstinner commented Jan 6, 2025

Copy link
Copy Markdown
Member Author

@serhiy-storchaka: I tried to implement all requested tests, but I skipped some of them for practical reasons.

On Windows, the file mode is limited to 10 characters. If it's a problem later, I can allocate memory on the heap and write more complicated code to handle longer modes. In practice, we should be fine with this arbitrary limit.

erlend-aasland reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@vstinner
vstinner merged commit f89e5e2 into python:main Jan 6, 2025
@vstinner
vstinner deleted the py_fopen branch January 6, 2025 12:43
@bedevere-app bedevere-app Bot removed the awaiting merge label Jan 6, 2025
@vstinner

vstinner commented Jan 6, 2025

Copy link
Copy Markdown
Member Author

PR merged, thanks for your reviews!

@serhiy-storchaka: You can write a follow-up PR if you want to extend the code coverage (add more tests).

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

srinivasreddy pushed a commit to srinivasreddy/cpython that referenced this pull request Jan 8, 2025
@vstinner @srinivasreddy
pythongh-127350: Add Py_fopen() and Py_fclose() functions (python#127821
a6bda81
)
@sonVishal sonVishal mentioned this pull request Jul 1, 2026
Py_fopen and Py_fclose not exported from python3.dll on Windows #152805
Closed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@serhiy-storchaka serhiy-storchaka serhiy-storchaka approved these changes
@zooba zooba zooba approved these changes
@erlend-aasland erlend-aasland erlend-aasland approved these changes
@ericsnowcurrently ericsnowcurrently Awaiting requested review from ericsnowcurrently ericsnowcurrently is a code owner
+1 more reviewer
@rruuaanng rruuaanng rruuaanng left review comments
Reviewers whose approvals may not affect merge requirements

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

6 participants

@vstinner @zooba @rruuaanng @PlanetCNC @serhiy-storchaka @erlend-aasland
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.