Skip to content

Commit 9c2521b

Browse files
authored
Merge pull request numpy#30965 from HaoZeke/fix/f2py-allocatable-dir
BUG: Show allocatable arrays in `dir()` for f2py modules
2 parents ea603c2 + 09f1a43 commit 9c2521b

3 files changed

Lines changed: 53 additions & 0 deletions

File tree

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``f2py`` modules now show allocatable arrays in ``dir()``
2+
---------------------------------------------------------
3+
Allocatable module variables wrapped by ``f2py`` now appear in ``dir()``
4+
output, matching their accessibility by name.

numpy/f2py/src/fortranobject.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,13 +576,55 @@ fortran_repr(PyFortranObject *fp)
576576
return repr;
577577
}
578578

579+
static PyObject *
580+
fortran_dir(PyFortranObject *fp, PyObject *Py_UNUSED(args))
581+
{
582+
int i;
583+
PyObject *dir_list = PyDict_Keys(fp->dict);
584+
if (dir_list == NULL) {
585+
return NULL;
586+
}
587+
for (i = 0; i < fp->len; i++) {
588+
PyObject *name = PyUnicode_FromString(fp->defs[i].name);
589+
if (name == NULL) {
590+
Py_DECREF(dir_list);
591+
return NULL;
592+
}
593+
int contains = PySequence_Contains(dir_list, name);
594+
if (contains == -1) {
595+
Py_DECREF(name);
596+
Py_DECREF(dir_list);
597+
return NULL;
598+
}
599+
if (!contains) {
600+
if (PyList_Append(dir_list, name) < 0) {
601+
Py_DECREF(name);
602+
Py_DECREF(dir_list);
603+
return NULL;
604+
}
605+
}
606+
Py_DECREF(name);
607+
}
608+
if (PyList_Sort(dir_list) < 0) {
609+
Py_DECREF(dir_list);
610+
return NULL;
611+
}
612+
return dir_list;
613+
}
614+
615+
static PyMethodDef fortran_methods[] = {
616+
{"__dir__", (PyCFunction)fortran_dir, METH_NOARGS, NULL},
617+
{NULL, NULL, 0, NULL}
618+
};
619+
579620
PyTypeObject PyFortran_Type = {
580621
PyVarObject_HEAD_INIT(NULL, 0).tp_name = "fortran",
581622
.tp_basicsize = sizeof(PyFortranObject),
582623
.tp_dealloc = (destructor)fortran_dealloc,
583624
.tp_getattr = (getattrfunc)fortran_getattr,
584625
.tp_setattr = (setattrfunc)fortran_setattr,
585626
.tp_repr = (reprfunc)fortran_repr,
627+
.tp_methods = fortran_methods,
586628
.tp_call = (ternaryfunc)fortran_call,
587629
};
588630

numpy/f2py/tests/test_modules.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,19 @@ class TestModuleAndSubroutine(util.F2PyTest):
5858
sources = [
5959
util.getpath("tests", "src", "modules", "gh25337", "data.f90"),
6060
util.getpath("tests", "src", "modules", "gh25337", "use_data.f90"),
61+
util.getpath("tests", "src", "regression", "datonly.f90"),
6162
]
6263

6364
def test_gh25337(self):
6465
self.module.data.set_shift(3)
6566
assert "data" in dir(self.module)
6667

68+
def test_allocatable_in_dir(self):
69+
# gh-27696: allocatable arrays should appear in dir()
70+
names = dir(self.module.datonly)
71+
assert "data_array" in names
72+
assert "max_value" in names
73+
6774

6875
@pytest.mark.slow
6976
class TestUsedModule(util.F2PyTest):

0 commit comments

Comments
 (0)