Skip to content

Instantly share code, notes, and snippets.

@sonictk
Last active March 5, 2019 17:14
Show Gist options
  • Save sonictk/e690837f819cb9c2b0b8 to your computer and use it in GitHub Desktop.
Save sonictk/e690837f819cb9c2b0b8 to your computer and use it in GitHub Desktop.
Generate Maya Python API 2.0 completion files
#!/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