Last active
March 5, 2019 17:14
-
-
Save sonictk/e690837f819cb9c2b0b8 to your computer and use it in GitHub Desktop.
Generate Maya Python API 2.0 completion files
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: UTF-8 -*- | |
""" | |
Module generate_om2_autocompletions: This module allows for automatically | |
generating completions files for the Maya Python 2.0 API. | |
""" | |
import os | |
import sys | |
import pydoc | |
import inspect | |
import maya.api.OpenMaya as om2 | |
import maya.api.OpenMayaAnim as om2_anim | |
import maya.api.OpenMayaUI as om2_ui | |
import maya.api.OpenMayaRender as om2_render | |
def get_docstring(item): | |
""" | |
This function returns the full docstring for the given object. | |
:param item: ``object`` that should have a ``__doc__`` attribute. | |
:return: ``str`` of full docstring. | |
""" | |
try: docstring = pydoc.plain(pydoc.render_doc(item)) | |
except ImportError: | |
docstring = '' | |
return docstring | |
def get_output_from_objects(nodes): | |
""" | |
This function returns formatted output from the objects given. | |
:param nodes: ``list`` of ``object``s to format data from. | |
:return: ``str`` formatted docstring and definition output. | |
""" | |
builtins_list = [ | |
'__class__', | |
'__delattr__', | |
'__doc__', | |
'__format__', | |
'__getattribute__', | |
'__hash__', | |
'__new__', | |
'__reduce__', | |
'__reduce_ex__', | |
'__setattr__', | |
'__sizeof__', | |
'__subclasshook__' | |
] | |
output = '' | |
for member in nodes: | |
# Format the docstring to have correct indentation | |
formatted_docstub = repr(member[1].__doc__) | |
formatted_docstub = '\t'+\ | |
formatted_docstub.replace('\\n', '\\n\\t').\ | |
replace('\'', '').\ | |
replace('\"', '').\ | |
decode('string-escape') | |
# Module-level objects (e.g. 'import maya') | |
if inspect.ismodule(member[1]): | |
# output += '\n\nimport {0}\n\n'.format(str(member[0])) | |
continue | |
elif inspect.isclass(member[1]): | |
# Find the next class inherited in the MRO and use that for | |
# the auto-completion entry | |
base_class = inspect.getmro(member[1]) | |
output += '\nclass {0}({1}):'.format(str(member[0]), base_class[1].__name__) | |
output += '\n\t\"\"\"\n'+formatted_docstub+'\n\t\"\"\"'+'\n\n' | |
class_members = inspect.getmembers(member[1]) | |
for member in class_members: | |
member_type = member[1] | |
member_name = member[0] | |
if member_name in builtins_list: | |
continue | |
# Instance variables | |
elif isinstance(member_type, int): | |
output += '\n\t{0} = {1}\n\n'.format(member[0], str(member[1])) | |
continue | |
# Class properties | |
elif inspect.isgetsetdescriptor(member_type): | |
output += '\t@property\n'.format(member_type.__class__.__name__) | |
# output += '\n\n TYPE: {0} \n\n'.format(member_type.__class__.__name__) | |
# Format class function definitions and their docstrings | |
member_docstring = repr(member[1].__doc__)\ | |
.replace('\\n', '\\r\\t\\t')\ | |
.replace('\'', '')\ | |
.replace('\"', '')\ | |
.decode('string-escape') | |
# todo: inspect arguments instead of using default *args, **kwargs | |
# for all accepted arugments. | |
output += '\r\t' + 'def {0}(self, *args, **kwargs):'.format(member_name) | |
output += '\r\t\t' + '\"\"\"\r\t\t{0}\r\t\t\"\"\"'.format(member_docstring) | |
output += '\r\t\tpass\n\n\n' | |
continue | |
elif inspect.ismethod(member[1]) or inspect.isfunction(member[1]): | |
output += '\ndef {0}():\r\tpass'.format(str(member[0])) | |
continue | |
elif inspect.isfunction(member[1]): | |
output += '\ndef {0}():\r\tpass'.format(str(member[0])) | |
continue | |
# Change tabs to spaces | |
output = output.replace('\t', ' ') | |
return output | |
def generate_completion_file( | |
module, | |
file_name=None, | |
boilerplate_headers=None, | |
output_file_path=None | |
): | |
""" | |
This function writes the completion file to the specified | |
output file path for the given modules. | |
:param module: ``object`` that is Python module to generate completion data for. | |
:param file_name: ``str`` that will be the file name written to for output. | |
:param boilerplate_headers: ``str`` containing any header data that is to | |
be appended to the beginning of the completion file. | |
:param output_file_path: ``str`` that is the file path to write the final | |
completion file to. | |
:return: ``None`` | |
""" | |
members = inspect.getmembers(module) | |
if not file_name: | |
file_name = module.__name__ | |
# Format boilerplate imports that go in the output | |
if boilerplate_headers: | |
output = boilerplate_headers | |
else: | |
output = '' | |
output += get_output_from_objects(members) | |
if not output_file_path: | |
output_file_path = os.path.join( | |
os.path.dirname( | |
os.path.dirname( | |
os.path.dirname(os.path.abspath(__file__) | |
) | |
) | |
), | |
'extras', | |
'om2_completions', | |
file_name + '.py' | |
) | |
if not os.path.isdir(os.path.dirname(output_file_path)): | |
os.makedirs(os.path.dirname(output_file_path)) | |
with open(output_file_path, 'w') as file_handle: | |
file_handle.write(output) | |
sys.stdout.write('Generated autocompletions file: {0} successfully!\n' | |
.format(output_file_path)) | |
def generate_autocompletions(boilerplate=''): | |
""" | |
This function, when run, generates the completion files. | |
:return: ``None`` | |
""" | |
# Generate completion files | |
try: | |
generate_completion_file(om2, 'OpenMaya', boilerplate) | |
generate_completion_file(om2_anim, 'OpenMayaAnim', boilerplate) | |
generate_completion_file(om2_render, 'OpenMayaRender', boilerplate) | |
generate_completion_file(om2_ui, 'OpenMayaUI', boilerplate) | |
except Exception: | |
sys.stderr.write('### Failed to generate all completion data!!!\n') | |
raise RuntimeError | |
sys.stdout.write('Successfully generated all completion file data!\n') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment