Developer Notes
Besides giving access to "raw" Python code, PythonObject is also the first step towards a full-fledged framework for creating Python package wrappers and developing Wolfram Language applications backed by Python code. To this end, it is possible to configure the wrappers to adhere closely to the Wolfram Language conventions. The framework also provides utility functions that make developing Python package wrappers simpler.
Configuration
Python package configurations can be defined interactively in the current Wolfram Language session or saved in a repository function and loaded on demand. In the future, saved configurations can be made discoverable automatically.
Configurations are defined through one or more of the PythonObject API functions including:
"WebInformation" | documentation and other links |
"NumberOfOptionalArguments" | promote options to optional arguments |
"Signatures" | set signatures of callable objects |
"PostProcess" | apply post-processing to Python results |
"PreProcess" | preprocess arguments before sending to Python |
"Rename" | use Wolfram Language naming conventions in Python objects |
"PreserveObjects" | keep specified Python-side objects as a single PythonObject |
"Normal" | define Normal for objects |
"Icon" | specify a custom icon |
"Dependencies" | load configurations for specified modules |
Currently, "Configuration"→Automatic uses the custom configuration, if defined, or the first non-custom configuration applied in the current Wolfram Language session.
Note: Although configurations can be loaded before or after a PythonObject is created, they do not apply retroactively.In most cases, to see the expected behavior, you have to create a new PythonObject instance after loading your configuration.
WebInformation (Experimental)
PythonObject["API","WebInformation"["package",<|key1→val1,…|>]]
defines URIs of the documention and other information for the package.
Possible keys include:
"DocumentationLink" | documentation URI |
"DocumentationSearchTemplate" | URI template for documentation search |
"DocumentationSearchTemplate" must give a StringTemplate expression to be applied to a search string.
Define the documentation link and the documentation search links for a package:
Open the web documentation link for a package in your default browser:
![](https://www.wolframcloud.com/obj/resourcesystem/images/6c8/6c8740c1-5a13-4c51-9ce2-df408cf026f8/1-2-0/61df17d4531325bc.png)
NumberOfOptionalArguments
In general, the convention to represent Python’s optional arguments as Wolfram Language options works well, but occasionally the design can be improved by keeping optional arguments at the same level with required positional arguments.
PythonObject["API","NumberOfOptionalArguments"["package",<|target1→n1,…|>]]
promotes the first n Python’s optional arguments in targeti in the specified package to Wolfram Language arguments.
"package" must be the package name or the name of the top-level module. targeti can be:
"func" | function |
{"class","method"} | method of the class |
A sample package that implements an "add_two" function":
Define a custom configuration in which the add_two function takes an optional argument, rather than an option:
Create a Python object for the package using the custom configuration:
The signature of the add_two function:
Call the function with one and two arguments:
For comparison, with no configuration, the second summand needs to be supplied as an option:
A package that defines a class and a function:
Set the number of optional arguments for the package function and all the methods in the class, using the "__init__" method to create an instance of the class and the "__call__" method to call it:
Create a class instance with one argument:
Create a second instance with an optional argument:
Call the second instance with one or two arguments:
Call a method:
Call the add_many function in the module:
For this function, one optional argument is left as an option:
Signatures
PythonObject["API","Signatures"["package",<|target1→assoc1,…|>]]
adds missing elements to signatures of the callable objects in the specified package.
targeti can be specified using the same conventions as for "NumberOfOptionalArguments".
Possible elements of associ include:
"Arguments" | list of arguements |
"Options" | list of options |
"IsMethod" | whether the callable is a method |
Signatures of some callable objects in this package contain missing elements:
Supply the signature of the function "log":
Now the function can be called as usual:
PostProcess
PythonObject["API","PostProcess"["package",func]]
applies the specified function to results received from the package.
The post-processor function func[e,{p,f},{farg1,farg2,…}]receives the result of the computation e; the caller object p, the name of the function or method f, and the list of arguments sent to f, including the arguments with default values.
For the module "uuid", define a post-processor function that converts the instances of the UUID class to their string values:
The Python object for the uuid.uuid4() function from the package:
Call the function:
For comparison, with no configuration, the function returns an instance of the UUID class:
PreProcess
PythonObject["API","PreProcess"["package",func]]
applies the specified function to Wolfram Language values before sending them to the package.
The preprocessor function func[{p,f},{arg1,arg2,…}]receives the caller object p, the name of the function or method f, and the list of arguments argi to be sent to f.
A sample package with a function that expects an immutable Python object, a tuple:
Define a custom configuration in which a Wolfram Language list is automatically converted to a tuple before sending it to the do_tuple function:
The Python object for the package:
Call the function:
For comparison, with no configuration, the function does not accept a mutable array object:
Rename
PythonObject["API","Rename"["package"]]
uses heuristic to rename function names, class names, methods and options in the package.
PythonObject["API","Rename"["package",{rules1,…}]]
sets up the specified name replacement rules.
Name replacements help to use Wolfram Language naming conventions.
For option names, replacement rules apply to both optional positional arguments, specified as "Options", and named arguments, specified as "KeywordOnlyArguments" and "KeywordArguments", as well as to those association keys in "KeywordArguments" that are defined as "KeywordOnlyArguments".
rulesi are applied in the specified order and can be either in the form suitable for the use in StringReplace or Automatic.
Automatic removes underscores and converts names to CamelCase.
The replacement rules allow the use of curated names, but do not mandate them. The original Python names can be used as well.
A sample package with one function:
Allow calling the function by its CamelCase name:
Create a Python object and call the function by its new name:
The native Python function name is still accessible:
Set up custom naming rules for the package:
Call the "get_approx" function using the new names:
Call the variable-arguments function with the new names:
Renaming rules for the package:
The rule for a particular name:
Convert to and from Python name:
PreserveObjects
PythonObject["API","PreserveObjects"["package",{obj1,obj2,…}]]
prevents obji from automatically expanding into components.
Certain Python-side objects are normally expanded into components by default:
Create a package with two functions, one that returns a tuple and another that expects a tuple argument:
Prevent tuples returned by the package from being automatically expanded:
Supply the tuple as argument:
Normal
PythonObject["API","Normal"["package",f]]
specifies that the function f should be applied to package objects to convert them to normal expressions.
If the function f is intended to be applied only to a subset of objects in the package, it must return Failure["ConditionFailure",…] for other objects.
Set up a rule to convert sparse SciPy matrices to SparseArray objects:
Create a sparse matrix in SciPy:
Convert the SciPy matrix to SparseArray:
Display the dense form:
Icon
PythonObject["API","Icon"["package",icon]]
specifies a custom icon for the package objects.
Specify an icon for objects in the SciPy package:
Dependencies
PythonObject["API","Dependencies"["package",assoc]]
specify dependencies for the package in the form <|"dep1"→configuration1,…|>.
Specify a dependency on the SciPy package:
Configure
PythonObject["API","Configure"["package",{func1,func2,…}]]
creates a configuration that includes all funci["package"].
Configuration functions funci are expected to be in the form "apif"[#,…]&, where "apif" is one of the configuration functions.
Allow calling my_function by a different name:
Miscellaneous Utilities
PythonObject["API","Reset"["package"]]
clears configuarations and cached values for the package.
PythonObject["API","Reset"[]]
clears configuarations and cached values for all packages defined in the current Wolfram Language session.
PythonObject["API","Reset"[All]] is the same as PythonObject["API","Reset"[]].
PythonObject["API","MissingSignatures"[p]]
gives a list of callables in the PythonObject p with missing or incomplete signatures.