ePolyglot: Examination and development of multilanguage programming using Eiffel, Python, and Haskell | ||
---|---|---|
Prev | Chapter 9. User Classes | Next |
It's relatively straightforward to write a script to generate code--in other words, to generate the Eiffel class file from a Python script. Even straightforward redefines of the module_name and class_name features are very easy to do. The problem lies in getting all the feature names from the class, and redefining them correctly.
Luckily, a solution is close at hand. All modules and classes are represented as objects in Python, and classes in particular sport a dictionary (cleverly named __dict__) which features all the function and attributes common to a class.
By examining the class object, and iterating through the members of __dict__, it's possible to examine each of those members and determine whether or not the member in question is a function, and if so whether or not it takes arguments (the number of arguments is fairly moot; Python executable objects take a tuple of arguments, and since Python is dynamically typed there really isn't any way to guess the desired type--so it's easier just to pass the Eiffel feature either a tuple of Python objects or an ARRAY of Eiffel objects)
For each function that is found, make_eiffel_stub.py generates both an Eiffel-arguments and Python-arguments stub for calling the feature. The name of the Eiffel feature is derived from the Python feature, with some changes to ensure more correct Eiffel names for features (no beginning with an underscore, no features having names identical to Eiffel keywords; that sort of thing).
The resultant Eiffel class is suitable for compilation, and can be used immediately; it and PYTHON_USER_CLASS take care of importing appropriate modules and initializing the class objects. When developing user-generated classes for which the Python code will be in the working directory of the application, developers should make sure to add the current directory to the Python sys.path feature in order for the interpreter to find it correctly--this can be done with the py_run_string function.