f90wrap icon indicating copy to clipboard operation
f90wrap copied to clipboard

Handling reserved Python words in f90wrap

Open nenanth opened this issue 4 years ago • 6 comments
trafficstars

@jameskermode I'm working with a legacy code that unfortunately has a derived type called "Size" (and for other reasons, I'm not allowed to rename it). Unfortunately, f90wrap does not seem to be able to auto-rename size to size_bn (as suggested by f2py).

I got far enough into f90wrap source to identify what appears to be a bug in f90wrapgen.py, line 785 ish. The dictionary key for self.types in RenameReservedWords still retains the name size, but the extra_uses invocation is extra_uses[self.types[t.name].mod_name] = [t.name] The entry t.name is not present in self.types, so I added a try/except to use t.orig_name on if the first one fails; would appreciate some guidance on whether it should also appear on the right hand side? I haven't fully tracked it down..

I tried this fix and it proceeded all the way to invoking f2py, at which point f2py complains that size_bn is being used before it is declared.. any help/pointers would be appreciated! I'm mostly stuck at figuring out where the derived type is renamed in the module before being compiled; I can "see" the individual elements in the derived type being renamed.

nenanth avatar Oct 13 '21 06:10 nenanth

I obtained a working solution by having f90wrap's fortran code generator completely ignore the renaming of types with reserved keywords (supposedly handled by f2py) and using .orig_name everywhere; what worked is when I got f90wrap's pywrapgen to implement the renaming of classes. However, I had to manually change source code for pywrapgen.py in the beginning of write_dt_wrappers to be

def write_dt_wrappers(self, node, el, properties):
      import numpy
      name_map = numpy.f2py.crackfortran.badnames
      if ft.strip_type(el.type) in name_map:
             cls_name = name_map[ft.strip_type(el.type)]

Then normalize the class name after filtering out reserved keywords cls_name = normalise_class_name(cls_name, self.class_names)

nenanth avatar Oct 13 '21 08:10 nenanth

That looks like an OK solution. Does f90wrap still pass all the regression tests? (make test in examples/) If so we could make that change in master. If you would be willing to make a PR which does this, and also adds a new test that would have shown the problem that would be great!

jameskermode avatar Oct 13 '21 08:10 jameskermode

Sure, I can make the PR after running the tests. Fingers crossed...

nenanth avatar Oct 13 '21 08:10 nenanth

Edit: nvm, found that I had to change python to python3 in the Makefile

@jameskermode it seems that some of the tests fail on master: the arrayderivedtype test failed on the master branch (i.e., without any of my changes) with the following error

Traceback (most recent call last):
  File "tests.py", line 23, in <module>
    import arrayderivedtype
  File "/Users/ananthsridharan/codes/f90wrap/examples/arrayderivedtypes/arrayderivedtype.py", line 2, in <module>
    import _arrayderivedtype
ImportError: No module named _arrayderivedtype
make[1]: *** [test] Error 1
make: *** [test] Error 2

nenanth avatar Oct 13 '21 18:10 nenanth

so all the default tests passed with my changes (good). Added a new test on my fork and making it more complex. Still working out nesting derived types with reserved names and catching/replacing all reserved words in all possible instances. Will post a PR when I'm happy with it

nenanth avatar Oct 13 '21 20:10 nenanth

@jameskermode I've submitted a PR with another test. There are edge cases like when a user creates an array of a derived type called size that start introducing ambiguity in the fortran compiler; this is a fortran error and I'm not accounting for those instances.

nenanth avatar Oct 14 '21 21:10 nenanth