Skip to content

Additionally expose multidict as a Cython importable#1178

Closed
Vizonex wants to merge 88 commits intoaio-libs:masterfrom
Vizonex:Cython-Compatability
Closed

Additionally expose multidict as a Cython importable#1178
Vizonex wants to merge 88 commits intoaio-libs:masterfrom
Vizonex:Cython-Compatability

Conversation

@Vizonex
Copy link
Copy Markdown
Member

@Vizonex Vizonex commented Jun 17, 2025

What do these changes do?

These changes add a new C-API for Cython support with multidict. This is my second attempt at getting this passed but this time I've added everything in to ensure a smooth pull request.

What I will mainly need help with is figuring out are the following parts

  • MultiDictProxy Objects
  • istr objects (I think we need to make a new function for initalizing istr in cython for a bit of extra speed)
  • documentation (I haven't figured out how we should approach this one. )

Are there changes in behavior for the user?

Users could now import multidict as a cython library which is something not very commonly seen I also added a get_include function for finding the multidict C Headers, will have to start including them for now on so that users will be able to compile them to cython or other C/C++ Apis.

Related issue number

Checklist

  • I think the code is well written
  • Unit tests for the changes exist
  • Documentation reflects the changes

@Vizonex Vizonex requested a review from asvetlov as a code owner June 17, 2025 21:13
@Vizonex Vizonex requested a review from webknjaz as a code owner June 17, 2025 21:18
@psf-chronographer psf-chronographer bot added the bot:chronographer:provided There is a change note present in this PR label Jun 17, 2025
@webknjaz
Copy link
Copy Markdown
Member

FYI, we got rid of Cython in #249

@asvetlov
Copy link
Copy Markdown
Member

asvetlov commented Jun 18, 2025

FYI, we got rid of Cython in #249

@webknjaz it is for fast calls of multidict methods from Cython, not for using Cython for the multidict implementation

Comment thread CHANGES/1178.feature.rst Outdated
Comment thread CHANGES/1178.feature.rst
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 where you can see a preview of how this change note is rendered: https://multidict--1178.org.readthedocs.build/en/1178/changes/. Alternatively, if you want to build the docs locally, it'll also include draft/unreleased notes.

Comment thread multidict/__init__.py Outdated
Comment on lines +66 to +67
"""Get multidict headers for compiling multidict with other
C Extensions or cython code"""
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 doesn't seem PEP 257-compliant. Could you organize it as a summary line and a separate description?

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.

Sure let me do so here in a bit I just woke up.

Comment thread multidict/__init__.py Outdated
Comment on lines +68 to +70
# NOTE: Import pathlib later so that were not being slow during
# other use-cases
import pathlib
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'm not sure if this is worth breaking the style for. Most people's apps would be importing pathlib anyway. So in real world, it'll likely be cached by the time multidict is imported.

Comment thread multidict/__init__.py

upstr = istr

# Inspired by Numpy
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.

Is this a comment for get_include()? Why is it several lines away from it? Code comments should be next to things they reference (ideally on the same line) so they don't drift even further away over time. Additionally, code comments should provide useful context that is otherwise unobvious, using complete sentenced (it is confusing to have 3 arbitrary words on a separate line without any other context that would at least seem related).
If you took this idea from elsewhere, it's of course good to give credit. But please also explain what the idea is in the first place.

Comment thread multidict/__init__.py
# other use-cases
import pathlib

return str(pathlib.Path(__file__).parent)
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.

Honestly, I'd avoid string-based path APIs. In Python, it's best to always use pathlib objects up until the point where strings are needed to interface with external systems. I think it's best to just return a pathlib object and let the caller convert it however they prefer. Maybe also .resolve() it before returning for a good measure.

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 function returns a value that should be added to a configuration, e.g. as -I cmdline option.
It's not a path to operate on; it's always processed as a string.

.resolve makes sense, though.

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 think it's not obvious to me (or probably @webknjaz) what the purpose of this function is? Is this some sort of standard interface to something?

It's not called anywhere in this PR and it's being exported as a public function. The docstring says it gets headers, but it appears to just return the path that multidict is installed in. Do people need this function, when they can just do multidict.__path__?

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.

@Dreamsorcerer good question.

I guess it could be used as Extension argument for third-party C extensions:

setup(...,
    extensions=[Extension(..., include_dirs=multidict.get_include())])

The same could be applied to third-party Cython extensions

multidict.__path__ could do the same, probably. I have no strong preference.

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.

Also, with the headers not being installed, is this unusable right now?

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.

Also, with the headers not being installed, is this unusable right now?

I think I solved that by editing manifest.in recently.

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.

That only governs what's included into sdists.

Comment thread multidict/_multidict.c Outdated
{
return PyModuleDef_Init(&multidict_module);
}

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.

accidental trailing line?

Suggested change

Comment thread multidict/_multidict.c Outdated
return 0;
}


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.

Looks like other sections follow a single-line separator convention between function definitions, only using double-lines where those sections end.

Suggested change

Regardless, we shouldn't include unrelated formatting because it surfaces arbitrary chunks of code in the PR diff.

FYI, #1123 proposes plugging a code formatter for C. If you'd like to work on it, this would solve the problem of accidentally changing things in PRs. And it'd be useful to all of us in general.

Comment thread requirements/dev.txt Outdated
-r towncrier.txt
-r doc.txt
pyperformance==1.11.0
cython==3.1.2
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.

Why is this needed? Where is it used?

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.

@webknjaz A little bit outdated but the plan was to use it for a cython test to ensure that the inner c-api to and from cython works correctly.

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.

Then put it into ci.txt and add a code comment that it's for capsule testing.

@webknjaz webknjaz changed the title Cython Extension for Multidict Additionally expose multidict as a Cython importable Jun 18, 2025
@webknjaz webknjaz requested a review from bdraco June 18, 2025 10:13
@Vizonex
Copy link
Copy Markdown
Member Author

Vizonex commented Jun 19, 2025

I'm stumped on writing the workflow to compiling the _multidict_cython test module that I wrote so I will simply wait for help.

Copy link
Copy Markdown
Member

@webknjaz webknjaz left a comment

Choose a reason for hiding this comment

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

There's a lot of cleaning to be done before this is mergeable. I marked some places related to what we talked about on matrix.

Comment thread MANIFEST.in
graft tests
global-exclude *.pyc
include multidict/*.c
include multidict/_multilib/*.h
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 adds the file to sdist. You may have to include it into wheels too.

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 will make sure I do so. Thanks for reminding me about wheels. I will get that done after I write some new documentation for using multidict with cython.

Comment thread .gitignore Outdated
Comment thread .github/workflows/ci-cd.yml Outdated
Comment thread Makefile Outdated
Comment thread multidict/__init__.py
# other use-cases
import pathlib

return str(pathlib.Path(__file__).parent)
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.

That only governs what's included into sdists.

Comment thread requirements/dev.txt Outdated
-r towncrier.txt
-r doc.txt
pyperformance==1.11.0
cython==3.1.2
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.

Then put it into ci.txt and add a code comment that it's for capsule testing.

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.

We should stop putting arbitrary artifacts into the test dir root. Ideally, they should just be generated and put into tmp dir. Or at least into a subdir.

Vizonex and others added 8 commits June 19, 2025 16:40
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <wk.cvs.github@sydorenko.org.ua>
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <wk.cvs.github@sydorenko.org.ua>
Co-authored-by: 🇺🇦 Sviatoslav Sydorenko (Святослав Сидоренко) <wk.cvs.github@sydorenko.org.ua>
@Vizonex
Copy link
Copy Markdown
Member Author

Vizonex commented Jun 20, 2025

Good news is that I did figure out that setuptools has no way to compile something without the setup portion so I came up with a workaround for it, cythonize was also pretty vague about this so that route turned out to just be a dead-end.

@Vizonex Vizonex mentioned this pull request Jun 20, 2025
@Vizonex
Copy link
Copy Markdown
Member Author

Vizonex commented Jun 20, 2025

Moved to #1183 I will be using this information I got from this one to help me later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:chronographer:provided There is a change note present in this PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants