-
-
Couldn't load subscription status.
- Fork 112
New MultiDict C-API functions And Added Documentation #1185
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
Conversation
…ent compile collisions with other libraries
|
Probably a good thing as well that I chose this route instead of the one I was going down I didn't feel as confused with what I was doing this time. |
…tigate a little bit more deeply...
for more information, see https://pre-commit.ci
|
After I sleep I will need to investigate This error I get when running pytest The other 2 tests work just fine except for md_new(0). |
|
I woke up time to finish this. |
|
@asvetlov I solved the problem with |
|
When I'm done testing the C stuff I will redo the Cython API in the same format as testcapi to keep things organized. |
|
there seems to be some bugs with |
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.
Looks good, thanks!
Please let me carefully re-read the source again a little later before the merging.
multidict/__init__.py
Outdated
| cython code | ||
| """ | ||
|
|
||
| return str(pathlib.Path(__file__).parent) |
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.
We have two options here.
- Drop the method, document
import multidict, include_path=multidict.__path__as I did intestcapi/setup.py - Keep the function but return bare
__path__;pathlibusage is redundant here
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.
@asvetlov There was an issue when I tried compiling it but it may have been a configuration problem on my end so met let me go back and revert this change.
|
@asvetlov I'm going to finish writing all the tests should we worry about patching up the bugs now or later? |
|
Only one thing is left on the table now will be debugging. |
|
@asvetlov Doesn't seem like I can merge this is there anything I'm missing that you would suggest I add before I start making more things later so that I don't overburden anyone? |
|
While I wait let me fill out the documentation for these new functions we added to the capi since I figured out how to do so. |
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.
Hey, I've left a bunch of comments.
Let's process them.
| static int | ||
| MultiDict_Clear(void* state_, PyObject* self) | ||
| { | ||
| // TODO: Macro for repeated steps being done? |
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.
Maybe the macro is a good idea, please feel free to try
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 will I moved to #1190 but I am making sure to read over all your suggestions real quick before I move on...
| return -1; | ||
| } | ||
| if (md_del((MultiDictObject*)self, key) < 0) { | ||
| PyErr_SetObject(PyExc_KeyError, key); |
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.
This line converts all errors (for example, TypeError if passed key is not a string) to KeyError; it is not good.
Better to just return a result of md_del() as is; md_del() already sets KeyError if the key is not found.
|
|
||
| static PyTypeObject * | ||
| MultiDict_GetType(void *state_) | ||
| /// @brief Gets the multidict type object |
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.
Regarding Doxigen comments -- I'm not sure if we need it.
We should either set up a Doxygen docs generator, as we already do for Sphinx docs, or we should drop these comments.
Without an automatic generator/checker, the comments eventually will go out of sync with the code itself; misleading comments are harmful.
Taking into account that we use Sphinx already, maybe better to document C API in sphinx also?
Aha, I see the comment that you already started Sphinx docs. In this case, Doxigen comments don't make sense.
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.
Aha, I see the comment that you already started Sphinx docs. In this case, Doxigen comments don't make sense.
I documented everything as I was writing everything so that moving things around would be less painful to move but I think we still need a readable format to have in the api header file incase some user decides to hover over the function and wonder what it's doing immediately. Msvc's C/C++ Extension seems to autogenerate these comments and allows me to see the definitions when I hover my mouse of them. However, I am willing to remove delete or reformat them all since I'm done moving the current sphinx documentation over.
| return NULL; | ||
| } | ||
| PyObject* ret = NULL; | ||
| if (md_get_one((MultiDictObject*)self, key, &ret) < 0) { |
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.
md_get_one() is designed to quickly figure out if the key exists or not without analyzing Python exception.
PyErr_ExceptionMatches() + PyErr_Clear() is much slower than if (ret == NULL).
I think MultiDict_GetOne() should follow PyDict_GetItemRef.
As I see, now md_get_one returns -1 if an exception was raised, 0 otherwise. Maybe better return 0 if not found, 1 if found. Let's do it in a separate PR against the master branch; the fix is not directly related to CAPI itself.
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.
As I see, now
md_get_onereturns-1if an exception was raised,0otherwise. Maybe better return0if not found,1if found. Let's do it in a separate PR against the master branch; the fix is not directly related to CAPI itself.
@asvetlov Sure, I would be willing to work on that when I'm done making fixes into this branch shouldn't be too difficult to port something like that into #1190 and another branch
| /// @return returns a default value on success, NULL is returned and raises | ||
| /// `TypeError` on failure | ||
| static PyObject* | ||
| MultiDict_Get(void* state_, PyObject* self, PyObject* key) |
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.
Do we need MultiDict_Get() if GetOne()/GetAll() also provided?
In python API, MultiDict.get() exists because multidict implements collections.abc.Mapping interface.
In C, we do not have such a contract.
If the function doesn't exist, nobody should learn how the function works.
| _invalid_type(); | ||
| return -1; | ||
| } | ||
| if (PyMapping_Check(other)) { |
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.
MultiDict_Check should go first. PyMapping_Check succeeds for multidict objects, which leads to a correct but slow path.
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.
Alright let me make sure it has that in #1190 then...
| /// @return 1 if true, 0 if false, -1 if failue occured follwed by raising a | ||
| /// TypeError | ||
| static int | ||
| MultiDict_Equals(void* state_, PyObject* self, PyObject* other) |
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 doubt if the function should be exposed; standard Python containers (dict, list, tuple, set) have no comparison functions, PyObject_RichCompare() does its job well.
The only exception is str, which has a rich set of comparison functions to work with objects, ascii and utf8 strings.
| */ | ||
|
|
||
| void *state; | ||
| void* state; |
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.
Cython branch will be setup once the C-API is done but I will keep it under the same format as the C-API and the module, the setup will be configured to same way as testcapi only this time I will name it testcythonapi.
Minor:testcapicould have two modules, one for C api test helpers and another one for Cython. Maybe we can even provide the same API by both wrappers to run the same api tests for both implementations, like we run the same tests suite for pure python and C extensions.
| { | ||
| mod_state *state = get_mod_state(self); | ||
| return MultiDict_New(state->capi, 0); | ||
| return Py_NewRef(MultiDict_New(state->capi, 0)); |
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.
This is suspicious.
MultiDict_New should return a new reference; double incref is not needed.
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.
Removing Py_NewRef here triggers Segfault when running in pytest tests\test_capi.py
tests\test_capi.py Windows fatal exception: access violation
Perhaps maybe I should move NewRef into Multidict_New instead?
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.
Or Maybe Py_INCREF?
|
|
||
| #define RETURN_NULL_OR_NEWREF(ITEM) \ | ||
| PyObject* REF = ITEM; \ | ||
| return (REF != NULL) ? Py_NewRef(REF) : NULL |
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.
Why newref here? It looks like a memory leak generation.
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.
My reasoning behind this was that not doing so would cause the program to segfault.
|
Sorry, I've merged the PR by accident; I'll revert the merge. |
|
I've reverted the merge into |
@asvetlov It's fine I'll try continuing where I left off in a new branch by just re-forking everything off again. |
What do these changes do?
First of all, thank you for giving something better to work with I really appreciate it.
This Adds a few new api calls mainly belonging to Multidict's api I had a proposed idea for an iterator but I think I might delete it and call it a day. I wasn't lazy at all about it in fact it encouraged me to keep going. I was pretty creative about exposing some functions such as MultiDicts updating each other or using Sequence and Mapping so that they could be utilized as shortcuts if needed.
Are there changes in behavior for the user?
Only the Good stuff is coming, I even wrote doxygen comments into each functions so that users would have a much better time using the C-API. Writing the pytest stuff is on my todo list I haven't done it yet but maybe sometime tomorrow I will finish this.
Related issue number
Checklist