-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
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
MAINT: Unify run_main()
and run_compile()
#25179
Comments
#24552 is related, but only tangentially. Bug for bug compatibility is great, and new features are great too but this is a matter of testing. For example #25114 is difficult to test because technically the behavior should be the same with or without |
I guess this comment #25199 (comment) is pertinent here as well. I have been looking at that part of the code in detail in the context of #25263. I am happy to contribute to this if we have general agreement on how to proceed, but I also found the distinction between |
@jmrohwer, I would really appreciate help streamlining this file. The problem is that there's global state populated in Note that (problematically) However, the goal would be to align them logically, that is:
I think for starters that would involve reducing What were your thoughts about this? |
@HaoZeke Thanks for getting back to me, I'm keen to be involved. I certainly don't have the bandwidth to refactor the whole CLI in terms of My main gripe with the current CLI is inconsistent behaviour (see also #25199 (comment)), specifically when using a custom edited *.pyf file to only expose some of the Fortran routines to Python. Consider
A user may want to use A further point is that I see in the code that in Before proceeding, we would need to agree and define exactly what is the expected behaviour for
in a situation as described. EDIT: I see the behaviour has changed again after #25267. The behaviour described above was before this commit.
This is confusing to say the least! |
Yup, that was the guideline for new flags (e.g.
This is also what the
It is difficult to say, technically until the minimum Python version supported in
The intent in #25267 was to ensure I think for:
This should ignore
This should behave the same as the previous, i.e. take the However, unfortunately something in #25267 broke |
At this point I feel like there's little else to do but bite the bullet and ensure |
Another data point: 5c5
< * Generation date: Fri Dec 1 11:42:08 2023
---
> * Generation date: Fri Dec 1 11:38:27 2023
23c23
< typedef signed char signed_char;
---
> /*need_typedefs*/
26c26
< typedef double(*cb_fun_in___user__routines_typedef)(int *);
---
> typedef double(*cb_fun_in_foo__user__routines_typedef)(int *);
47,53d46
< #define GETSCALARFROMPYTUPLE(tuple,index,var,ctype,mess) {\
< if ((capi_tmp = PyTuple_GetItem((tuple),(index)))==NULL) goto capi_fail;\
< if (!(ctype ## _from_pyobj((var),capi_tmp,mess)))\
< goto capi_fail;\
< }
<
< #define pyobj_from_int1(v) (PyInt_FromLong(v))
107,145d99
< static int double_from_pyobj(double* v,PyObject *obj,const char *errmess) {
< PyObject* tmp = NULL;
< if (PyFloat_Check(obj)) {
< #ifdef __sgi
< *v = PyFloat_AsDouble(obj);
< #else
< *v = PyFloat_AS_DOUBLE(obj);
< #endif
< return 1;
< }
< tmp = PyNumber_Float(obj);
< if (tmp) {
< #ifdef __sgi
< *v = PyFloat_AsDouble(tmp);
< #else
< *v = PyFloat_AS_DOUBLE(tmp);
< #endif
< Py_DECREF(tmp);
< return 1;
< }
< if (PyComplex_Check(obj))
< tmp = PyObject_GetAttrString(obj,"real");
< else if (PyString_Check(obj) || PyUnicode_Check(obj))
< /*pass*/;
< else if (PySequence_Check(obj))
< tmp = PySequence_GetItem(obj,0);
< if (tmp) {
< PyErr_Clear();
< if (double_from_pyobj(v,tmp,errmess)) {Py_DECREF(tmp); return 1;}
< Py_DECREF(tmp);
< }
< {
< PyObject* err = PyErr_Occurred();
< if (err==NULL) err = callback2_error;
< PyErr_SetString(err,errmess);
< }
< return 0;
< }
<
262c216
< extern void F_FUNC(foo,FOO)(cb_fun_in___user__routines_typedef,double*);
---
> extern void F_FUNC(foo,FOO)(cb_fun_in_foo__user__routines_typedef,double*);
270,277c224,231
< /************************* cb_fun_in___user__routines *************************/
< PyObject *cb_fun_in___user__routines_capi = NULL;/*was Py_None*/
< PyTupleObject *cb_fun_in___user__routines_args_capi = NULL;
< int cb_fun_in___user__routines_nofargs = 0;
< jmp_buf cb_fun_in___user__routines_jmpbuf;
< /*typedef double(*cb_fun_in___user__routines_typedef)(int *);*/
< static double cb_fun_in___user__routines (int *i_cb_capi) {
< PyTupleObject *capi_arglist = cb_fun_in___user__routines_args_capi;
---
> /*********************** cb_fun_in_foo__user__routines ***********************/
> PyObject *cb_fun_in_foo__user__routines_capi = NULL;/*was Py_None*/
> PyTupleObject *cb_fun_in_foo__user__routines_args_capi = NULL;
> int cb_fun_in_foo__user__routines_nofargs = 0;
> jmp_buf cb_fun_in_foo__user__routines_jmpbuf;
> /*typedef double(*cb_fun_in_foo__user__routines_typedef)(int *);*/
> static double cb_fun_in_foo__user__routines (int *i_cb_capi) {
> PyTupleObject *capi_arglist = cb_fun_in_foo__user__routines_args_capi;
289,291c243,245
< CFUNCSMESS("cb:Call-back function cb_fun_in___user__routines (maxnofargs=1(-0))\n");
< CFUNCSMESSPY("cb:cb_fun_in___user__routines_capi=",cb_fun_in___user__routines_capi);
< if (cb_fun_in___user__routines_capi==NULL) {
---
> CFUNCSMESS("cb:Call-back function cb_fun_in_foo__user__routines (maxnofargs=1(-0))\n");
> CFUNCSMESSPY("cb:cb_fun_in_foo__user__routines_capi=",cb_fun_in_foo__user__routines_capi);
> if (cb_fun_in_foo__user__routines_capi==NULL) {
293c247
< cb_fun_in___user__routines_capi = PyObject_GetAttrString(callback2_module,"fun");
---
> cb_fun_in_foo__user__routines_capi = PyObject_GetAttrString(callback2_module,"fun");
295c249
< if (cb_fun_in___user__routines_capi==NULL) {
---
> if (cb_fun_in_foo__user__routines_capi==NULL) {
299,302c253,256
< if (F2PyCapsule_Check(cb_fun_in___user__routines_capi)) {
< cb_fun_in___user__routines_typedef cb_fun_in___user__routines_cptr;
< cb_fun_in___user__routines_cptr = F2PyCapsule_AsVoidPtr(cb_fun_in___user__routines_capi);
< return_value=(*cb_fun_in___user__routines_cptr)(i_cb_capi);
---
> if (F2PyCapsule_Check(cb_fun_in_foo__user__routines_capi)) {
> cb_fun_in_foo__user__routines_typedef cb_fun_in_foo__user__routines_cptr;
> cb_fun_in_foo__user__routines_cptr = F2PyCapsule_AsVoidPtr(cb_fun_in_foo__user__routines_capi);
> return_value=(*cb_fun_in_foo__user__routines_cptr)(i_cb_capi);
332c286
< if (cb_fun_in___user__routines_nofargs>capi_i)
---
> if (cb_fun_in_foo__user__routines_nofargs>capi_i)
346c300
< capi_return = PyObject_CallObject(cb_fun_in___user__routines_capi,(PyObject *)capi_arglist_list);
---
> capi_return = PyObject_CallObject(cb_fun_in_foo__user__routines_capi,(PyObject *)capi_arglist_list);
350c304
< capi_return = PyObject_CallObject(cb_fun_in___user__routines_capi,(PyObject *)capi_arglist);
---
> capi_return = PyObject_CallObject(cb_fun_in_foo__user__routines_capi,(PyObject *)capi_arglist);
371,372c325,326
< GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,double,"double_from_pyobj failed in converting return_value of call-back function cb_fun_in___user__routines to C double\n");
< CFUNCSMESS("cb:cb_fun_in___user__routines:successful\n");
---
> GETSCALARFROMPYTUPLE(capi_return,capi_i++,&return_value,double,"double_from_pyobj failed in converting return_value of call-back function cb_fun_in_foo__user__routines to C double\n");
> CFUNCSMESS("cb:cb_fun_in_foo__user__routines:successful\n");
379c333
< fprintf(stderr,"Call-back cb_fun_in___user__routines failed.\n");
---
> fprintf(stderr,"Call-back cb_fun_in_foo__user__routines failed.\n");
383c337
< longjmp(cb_fun_in___user__routines_jmpbuf,-1);
---
> longjmp(cb_fun_in_foo__user__routines_jmpbuf,-1);
388c342
< /********************* end of cb_fun_in___user__routines *********************/
---
> /******************** end of cb_fun_in_foo__user__routines ********************/
395c349
< r = foo(f,[f_extra_args])\n\nWrapper for ``foo``.\
---
> r = foo(fun,[fun_extra_args])\n\nWrapper for ``foo``.\
397c351
< "f : call-back function => fun\n"
---
> "fun : call-back function\n"
399c353
< "f_extra_args : input tuple, optional\n Default: ()\n"
---
> "fun_extra_args : input tuple, optional\n Default: ()\n"
408c362
< /* extern void F_FUNC(foo,FOO)(cb_fun_in___user__routines_typedef,double*); */
---
> /* extern void F_FUNC(foo,FOO)(cb_fun_in_foo__user__routines_typedef,double*); */
412c366
< void (*f2py_func)(cb_fun_in___user__routines_typedef,double*)) {
---
> void (*f2py_func)(cb_fun_in_foo__user__routines_typedef,double*)) {
417,421c371,375
< PyObject *f_capi = Py_None;
< PyTupleObject *f_xa_capi = NULL;
< PyTupleObject *f_args_capi = NULL;
< int f_nofargs_capi = 0;
< cb_fun_in___user__routines_typedef f_cptr;
---
> PyObject *fun_capi = Py_None;
> PyTupleObject *fun_xa_capi = NULL;
> PyTupleObject *fun_args_capi = NULL;
> int fun_nofargs_capi = 0;
> cb_fun_in_foo__user__routines_typedef fun_cptr;
423c377
< static char *capi_kwlist[] = {"f","f_extra_args",NULL};
---
> static char *capi_kwlist[] = {"fun","fun_extra_args",NULL};
431c385
< capi_kwlist,&f_capi,&PyTuple_Type,&f_xa_capi))
---
> capi_kwlist,&fun_capi,&PyTuple_Type,&fun_xa_capi))
434,436c388,390
< /* Processing variable f */
< if(F2PyCapsule_Check(f_capi)) {
< f_cptr = F2PyCapsule_AsVoidPtr(f_capi);
---
> /* Processing variable fun */
> if(F2PyCapsule_Check(fun_capi)) {
> fun_cptr = F2PyCapsule_AsVoidPtr(fun_capi);
438c392
< f_cptr = cb_fun_in___user__routines;
---
> fun_cptr = cb_fun_in_foo__user__routines;
441,447c395,401
< f_nofargs_capi = cb_fun_in___user__routines_nofargs;
< if (create_cb_arglist(f_capi,f_xa_capi,1,0,&cb_fun_in___user__routines_nofargs,&f_args_capi,"failed in processing argument list for call-back f.")) {
< jmp_buf f_jmpbuf;
< CFUNCSMESS("Saving jmpbuf for `f`.\n");
< SWAP(f_capi,cb_fun_in___user__routines_capi,PyObject);
< SWAP(f_args_capi,cb_fun_in___user__routines_args_capi,PyTupleObject);
< memcpy(&f_jmpbuf,&cb_fun_in___user__routines_jmpbuf,sizeof(jmp_buf));
---
> fun_nofargs_capi = cb_fun_in_foo__user__routines_nofargs;
> if (create_cb_arglist(fun_capi,fun_xa_capi,1,0,&cb_fun_in_foo__user__routines_nofargs,&fun_args_capi,"failed in processing argument list for call-back fun.")) {
> jmp_buf fun_jmpbuf;
> CFUNCSMESS("Saving jmpbuf for `fun`.\n");
> SWAP(fun_capi,cb_fun_in_foo__user__routines_capi,PyObject);
> SWAP(fun_args_capi,cb_fun_in_foo__user__routines_args_capi,PyTupleObject);
> memcpy(&fun_jmpbuf,&cb_fun_in_foo__user__routines_jmpbuf,sizeof(jmp_buf));
454c408
< if ((setjmp(cb_fun_in___user__routines_jmpbuf))) {
---
> if ((setjmp(cb_fun_in_foo__user__routines_jmpbuf))) {
457c411
< (*f2py_func)(f_cptr,&r);
---
> (*f2py_func)(fun_cptr,&r);
475,480c429,434
< CFUNCSMESS("Restoring jmpbuf for `f`.\n");
< cb_fun_in___user__routines_capi = f_capi;
< Py_DECREF(cb_fun_in___user__routines_args_capi);
< cb_fun_in___user__routines_args_capi = f_args_capi;
< cb_fun_in___user__routines_nofargs = f_nofargs_capi;
< memcpy(&cb_fun_in___user__routines_jmpbuf,&f_jmpbuf,sizeof(jmp_buf));
---
> CFUNCSMESS("Restoring jmpbuf for `fun`.\n");
> cb_fun_in_foo__user__routines_capi = fun_capi;
> Py_DECREF(cb_fun_in_foo__user__routines_args_capi);
> cb_fun_in_foo__user__routines_args_capi = fun_args_capi;
> cb_fun_in_foo__user__routines_nofargs = fun_nofargs_capi;
> memcpy(&cb_fun_in_foo__user__routines_jmpbuf,&fun_jmpbuf,sizeof(jmp_buf));
482c436
< /* End of cleaning variable f */
---
> /* End of cleaning variable fun */
548c502
< " r = foo(f,f_extra_args=())\n"
---
> " r = foo(fun,fun_extra_args=())\n" So it will likely not work with |
Currently
f2py
has two separate paths withinf2py2e
which do "almost the same thing".run_main
is supposed to do everything but-c
andrun_compile()
is supposed to compile to a module. There is a lot of technical debt being carried here,run_compile()
shouldn't be doing anything different fromrun_main
in the first place. This also leads to subtle bugs since the results of-c
and regularf2py
runs are often different. It also makes it hard to test the CLI well (at the very least, doubles the number of possible tests).The text was updated successfully, but these errors were encountered: