├── .coveralls.yml ├── .gitignore ├── .landscape.yml ├── .travis.yml ├── MANIFEST.in ├── README.rst ├── docs ├── Makefile ├── make.bat └── source │ ├── _static │ └── stylesheet.css │ ├── _templates │ └── layout.html │ ├── conf.py │ └── index.rst ├── maya_signatures ├── __init__.py ├── cli.py ├── commands │ ├── __init__.py │ ├── base.py │ ├── cache.py │ └── scrape.py └── version.py ├── requirements.txt ├── scrape.json ├── setup.cfg ├── setup.py ├── tests └── test_scrape.py └── tox.ini /.coveralls.yml: -------------------------------------------------------------------------------- 1 | repo_token: PR8kZREFJRhslwdfA5MSzyENscoSiHw1K 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .idea/ 11 | .Python 12 | env/ 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # Jupyter Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # SageMath parsed files 81 | *.sage.py 82 | 83 | # dotenv 84 | .env 85 | 86 | # virtualenv 87 | .venv 88 | venv/ 89 | ENV/ 90 | 91 | # Spyder project settings 92 | .spyderproject 93 | .spyproject 94 | 95 | # Rope project settings 96 | .ropeproject 97 | 98 | # mkdocs documentation 99 | /site 100 | -------------------------------------------------------------------------------- /.landscape.yml: -------------------------------------------------------------------------------- 1 | doc-warnings: true 2 | test-warnings: false 3 | strictness: veryhigh 4 | max-line-length: 120 5 | autodetect: true 6 | pep8: 7 | full: true 8 | requirements: 9 | - requirements.txt 10 | ignore-paths: 11 | - docs 12 | - build 13 | - dist 14 | - .cache 15 | - .tox 16 | - .idea 17 | - .coverage 18 | - .git 19 | ignore-patterns: 20 | - ^example/doc_.*\.py$ 21 | - (^|/)docs(/|$) 22 | - ^.+.egg-info$ 23 | python-targets: 24 | - 2 25 | - 3 -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '3.6' 4 | - '2.7' 5 | before_install: 6 | install: 7 | - pip install tox-travis 8 | - pip install . 9 | - pip install coveralls 10 | script: 11 | - tox 12 | 13 | deploy: 14 | provider: pypi 15 | user: andresmweber 16 | password: 17 | secure: K5j0P2HjfblSsDLtOCsvZd5T4ljuyqUPucWlgB6TYA1vQ7UhvuwTf4KNe9hyVgXcqyfYR1p/woGvXyklFN5OffdHoYoKuYIH/zfEFYT54qtlKuvj369mJ4okNhQq9lCo24CO4U/Kqxsnc7KWW3B0dtjrE2zCowIAfJxBsOUN21ityjoo3y7/jPICh9JOCmkntifhRNdZOsj7xThn2PUcA3iKtqc5Xy6z4H+VmyKfS54kGKbI+Fmckg4/xaC9QchGEHIUglSLs/7hHqvaHA0/8dMsVaqARV3S+93A+jE3opqIs5o5gYwXMfIJJhn4RciJn0GPiRggd3647aQO3Gx6XH/kkD1hNnNHXv3CNOsxa4ArAA7RuHGZlG5T7kpFeuQ0CrqpTK4e6RXbpyQVdxkIBi5E1GLaGlEGTtYMQkbJHKC7s0eKpa19PJgnSufl8smkpyvQkusKUz5JOwhEKvc8pyEx20h+41x1yRKX87NDiP7LyCQoYbqRsy82MMO94Qxj8Fnyr3jS8KuC7M558WQ0HLwih8Zod/j4PTIr4CtgVhQL+Q6bEEcrRXm4yTTDrzHPqoeSGbDDTe4IwkzRSC9oXeF0WcpMltkqzRF1xF1Md5GTbaia7QwDuhIMAL9AwA5YLB4Eivm/TdIHiCTERUHwlAVof+M25BY0wIuSBtWxlTs= 18 | on: 19 | tags: true 20 | all_branches: true 21 | distributions: sdist bdist_wheel 22 | repo: AndresMWeber/maya-cmds-help 23 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | # MANIFEST.in 2 | exclude .gitignore 3 | exclude .coverage 4 | exclude .travis.yml 5 | include README.rst 6 | include setup.cfg 7 | prune .cache 8 | prune .git 9 | prune build 10 | prune dist 11 | recursive-exclude *.egg-info * 12 | recursive-include tests * 13 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | maya-cmds-help: For people who just really want to check their maya.cmds signatures 2 | ################################################################################################### 3 | `Online Documentation (ReadTheDocs) `_ 4 | 5 | .. image:: https://badge.fury.io/py/Maya-Signature-Scraper.svg 6 | :target: https://badge.fury.io/py/Maya-Signature-Scraper 7 | 8 | .. image:: https://travis-ci.org/AndresMWeber/mayasig_cli.svg?branch=master 9 | :target: https://travis-ci.org/AndresMWeber/mayasig_cli 10 | 11 | .. image:: https://coveralls.io/repos/github/AndresMWeber/mayasig_cli/badge.svg?branch=master 12 | :target: https://coveralls.io/github/AndresMWeber/mayasig_cli?branch=master 13 | 14 | .. image:: https://landscape.io/github/AndresMWeber/maya-cmds-help/master/landscape.svg?style=flat 15 | :target: https://landscape.io/github/AndresMWeber/maya-cmds-help/master 16 | :alt: Code Health 17 | 18 | .. contents:: 19 | 20 | .. section-numbering:: 21 | 22 | Synopsis 23 | ============= 24 | 25 | If you're looking into this tool, you're looking for a programmatic way of getting Maya function signatures. The current version of the tool has unfiltered prints as status logs...so that might be a deterrent... I personally built it so that I could compare my maya command calls against kwargs/args Maya expects to reduce errors. 26 | 27 | Hope you'll find it useful! Once you install you will now have a CLI tool called mayasig. 28 | 29 | Features 30 | -------- 31 | - Caching 32 | - Up to date with online help docs 33 | - Temp file generator 34 | - JSON file output 35 | - CLI access 36 | - Dict output 37 | 38 | Installation 39 | ============ 40 | Windows, etc. 41 | ------------- 42 | A universal installation method (that works on Windows, Mac OS X, Linux, …, and always provides the latest version) is to use `pip`: 43 | 44 | .. code-block:: bash 45 | 46 | # Make sure we have an up-to-date version of pip and setuptools: 47 | $ pip install --upgrade pip setuptools 48 | $ pip install maya-cmds-help 49 | 50 | 51 | (If ``pip`` installation fails for some reason, you can try 52 | ``easy_install maya-cmds-help`` as a fallback.) 53 | 54 | Usage 55 | ============= 56 | 57 | Bash 58 | ------------ 59 | 60 | .. code-block:: bash 61 | 62 | mayasig 63 | 64 | Usage: 65 | mayasig [-m|--mayaversion VERSION] [-d|--depth DEPTH] (MAYA_CMDS ...) 66 | mayasig (-h|--help) 67 | mayasig (--version) 68 | 69 | Options: 70 | -h --help Show this screen. 71 | --version Show version. 72 | -m VERSION --mayaversion VERSION If you want to override which Maya docs we query (tested with 2015/2016/2017) [default: 2017] 73 | -d DEPTH --depth DEPTH The depth verbosity of the return dictionary [default: 1] 74 | MAYA_CMDS Maya commands to query/scrape from the help and return signatures for 75 | 76 | Examples: 77 | mayasig group 78 | 79 | Help: 80 | For help using this tool, please open an issue on the Github repository: 81 | https://github.com/andresmweber/mayasig-cli 82 | 83 | Python Package Usage 84 | --------------------- 85 | Feel free to access from the package instead via the two package-level convenience functions: 86 | 87 | .. code-block:: python 88 | 89 | maya_signatures.CACHE 90 | maya_signatures.query 91 | 92 | In order to access full functionality from the scraper class you can access a package level instance of maya_signatures.commands.scrape.Scraper using: 93 | 94 | .. code-block:: python 95 | 96 | maya_signatures.SCRAPER 97 | 98 | 99 | .. code-block:: python 100 | 101 | import maya_signatures 102 | maya_signatures.query('ls') 103 | # Result: 104 | # storing args ('ls',) storing kwargs {} 105 | # Successfully loaded json data, loading into cache... 106 | # Retrieving cached value for input http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/ls.html 107 | # wrote out tmp file C:\Users\andre\dev\maya_signature_builder\scrape.json 108 | 109 | maya_signatures.SCRAPER.build_command_stub('ls') 110 | # Result: def ls(*args, textures=bool, selection=bool, defaultNodes=bool, templated=bool, visible=bool, references=bool, flatten=bool, nodeTypes=bool, persistentNodes=bool, intermediateObjects=bool, long=bool, leaf=bool, recursive=bool, objectsOnly=bool, lockedNodes=bool, cameras=bool, tail=int, absoluteName=bool, lights=bool, live=bool, renderSetups=bool, containerType=str, preSelectHilite=bool, type=str, containers=bool, shortNames=bool, renderResolutions=bool, head=int, showType=bool, dependencyNodes=bool, orderedSelection=bool, renderQualities=bool, readOnly=bool, referencedNodes=bool, showNamespace=bool, invisible=bool, hilite=bool, untemplated=bool, partitions=bool, ghost=bool, uuid=bool, sets=bool, geometry=bool, assemblies=bool, noIntermediate=bool, modified=bool, allPaths=bool, shapes=bool, materials=bool, excludeType=str, planes=bool, exactType=str, renderGlobals=bool, undeletable=bool, dagObjects=bool, transforms=bool): 111 | # pass 112 | 113 | .. code-block:: python 114 | 115 | maya_signatures.query('group') 116 | # Result: storing args ('group',) storing kwargs {} 117 | # Successfully loaded json data, loading into cache... 118 | # Could not find key http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/group.html in cached values...retrieving... 119 | # Trying to find command for web page: 120 | # http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/group.html 121 | # wrote out tmp file C:\Users\andre\dev\maya_signature_builder\scrape.json 122 | maya_signatures.SCRAPER.get_command_flags('group') 123 | # Result: [('name', 'n'), ('parent', 'p'), ('relative', 'r'), ('useAsGroup', 'uag'), ('world', 'w'), ('empty', 'em'), ('absolute', 'a')] 124 | 125 | 126 | Version Support 127 | =============== 128 | This package supports the Maya 2015, 2016 and 2017 help docs so far so please be aware. 129 | I might back port a couple versions of the maya online help, but this is totally dependent on time. 130 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | SPHINXPROJ = MayaCommandSignatureScraper 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | set SPHINXPROJ=MayaCommandSignatureScraper 13 | 14 | if "%1" == "" goto help 15 | 16 | %SPHINXBUILD% >NUL 2>NUL 17 | if errorlevel 9009 ( 18 | echo. 19 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 20 | echo.installed, then set the SPHINXBUILD environment variable to point 21 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 22 | echo.may add the Sphinx directory to PATH. 23 | echo. 24 | echo.If you don't have Sphinx installed, grab it from 25 | echo.http://sphinx-doc.org/ 26 | exit /b 1 27 | ) 28 | 29 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 30 | goto end 31 | 32 | :help 33 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% 34 | 35 | :end 36 | popd 37 | -------------------------------------------------------------------------------- /docs/source/_static/stylesheet.css: -------------------------------------------------------------------------------- 1 | .wy-nav-content { 2 | max-width: 1500px !important; 3 | } 4 | -------------------------------------------------------------------------------- /docs/source/_templates/layout.html: -------------------------------------------------------------------------------- 1 | {% extends "!layout.html" %} 2 | {% block extrahead %} 3 | 4 | {% endblock %} 5 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # maya-cmds-help documentation build configuration file, created by 4 | # sphinx-quickstart on Fri May 05 00:02:58 2017. 5 | # 6 | # This file is execfile()d with the current directory set to its 7 | # containing dir. 8 | # 9 | # Note that not all possible configuration values are present in this 10 | # autogenerated file. 11 | # 12 | # All configuration values have a default; values that are commented out 13 | # serve to show the default. 14 | 15 | # If extensions (or modules to document with autodoc) are in another directory, 16 | # add these directories to sys.path here. If the directory is relative to the 17 | # documentation root, use os.path.abspath to make it absolute, like shown here. 18 | # 19 | # import os 20 | # import sys 21 | # sys.path.insert(0, os.path.abspath('.')) 22 | 23 | 24 | # -- General configuration ------------------------------------------------ 25 | 26 | # If your documentation needs a minimal Sphinx version, state it here. 27 | # 28 | # needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = ['sphinx.ext.autodoc', 34 | 'sphinx.ext.doctest', 35 | 'sphinx.ext.coverage', 36 | 'sphinx.ext.viewcode'] 37 | 38 | # Add any paths that contain templates here, relative to this directory. 39 | templates_path = ['_templates'] 40 | 41 | # The suffix(es) of source filenames. 42 | # You can specify multiple suffix as a list of string: 43 | # 44 | # source_suffix = ['.rst', '.md'] 45 | source_suffix = '.rst' 46 | 47 | # The master toctree document. 48 | master_doc = 'index' 49 | 50 | # General information about the project. 51 | project = u'maya-cmds-help' 52 | copyright = u'2017, Andres Weber' 53 | author = u'Andres Weber' 54 | 55 | # The version info for the project you're documenting, acts as replacement for 56 | # |version| and |release|, also used in various other places throughout the 57 | # built documents. 58 | # 59 | # The short X.Y version. 60 | print(dir(__import__('maya_signatures'))) 61 | # version = __import__('maya_signatures').__version__ 62 | # The full version, including alpha/beta/rc tags. 63 | # release = __import__('maya_signatures').__version__ 64 | 65 | # The language for content autogenerated by Sphinx. Refer to documentation 66 | # for a list of supported languages. 67 | # 68 | # This is also used if you do content translation via gettext catalogs. 69 | # Usually you set "language" from the command line for these cases. 70 | language = None 71 | 72 | # List of patterns, relative to source directory, that match files and 73 | # directories to ignore when looking for source files. 74 | # This patterns also effect to html_static_path and html_extra_path 75 | exclude_patterns = [] 76 | 77 | # The name of the Pygments (syntax highlighting) style to use. 78 | pygments_style = 'sphinx' 79 | 80 | # If true, `todo` and `todoList` produce output, else they produce nothing. 81 | todo_include_todos = False 82 | 83 | # -- Options for HTML output ---------------------------------------------- 84 | 85 | # The theme to use for HTML and HTML Help pages. See the documentation for 86 | # a list of builtin themes. 87 | # 88 | html_theme = 'alabaster' 89 | 90 | # Theme options are theme-specific and customize the look and feel of a theme 91 | # further. For a list of options available for each theme, see the 92 | # documentation. 93 | # 94 | # html_theme_options = {} 95 | 96 | # Add any paths that contain custom static files (such as style sheets) here, 97 | # relative to this directory. They are copied after the builtin static files, 98 | # so a file named "default.css" will overwrite the builtin "default.css". 99 | html_static_path = ['_static'] 100 | 101 | # -- Options for HTMLHelp output ------------------------------------------ 102 | 103 | # Output file base name for HTML help builder. 104 | htmlhelp_basename = 'maya-cmds-help-doc' 105 | 106 | # -- Options for LaTeX output --------------------------------------------- 107 | 108 | latex_elements = { 109 | # The paper size ('letterpaper' or 'a4paper'). 110 | # 111 | # 'papersize': 'letterpaper', 112 | 113 | # The font size ('10pt', '11pt' or '12pt'). 114 | # 115 | # 'pointsize': '10pt', 116 | 117 | # Additional stuff for the LaTeX preamble. 118 | # 119 | # 'preamble': '', 120 | 121 | # Latex figure (float) alignment 122 | # 123 | # 'figure_align': 'htbp', 124 | } 125 | 126 | # Grouping the document tree into LaTeX files. List of tuples 127 | # (source start file, target name, title, 128 | # author, documentclass [howto, manual, or own class]). 129 | latex_documents = [ 130 | (master_doc, 'maya-cmds-help.tex', u'maya-cmds-help Documentation', 131 | u'Andres Weber', 'manual'), 132 | ] 133 | 134 | # -- Options for manual page output --------------------------------------- 135 | 136 | # One entry per manual page. List of tuples 137 | # (source start file, name, description, authors, manual section). 138 | man_pages = [ 139 | (master_doc, 'maya-cmds-help', u'maya-cmds-help Documentation', 140 | [author], 1) 141 | ] 142 | 143 | # -- Options for Texinfo output ------------------------------------------- 144 | 145 | # Grouping the document tree into Texinfo files. List of tuples 146 | # (source start file, target name, title, author, 147 | # dir menu entry, description, category) 148 | texinfo_documents = [ 149 | (master_doc, 'maya-cmds-help', u'maya-cmds-help Documentation', 150 | author, 'maya-cmds-help', 'One line description of project.', 151 | 'Miscellaneous'), 152 | ] 153 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Maya Command Signature Scraper: For people who just really want to check their maya.cmds signatures 2 | ################################################################################################### 3 | `Online Documentation (ReadTheDocs) `_ 4 | 5 | .. image:: https://badge.fury.io/py/Maya-Signature-Scraper.svg 6 | :target: https://badge.fury.io/py/Maya-Signature-Scraper 7 | 8 | .. image:: https://travis-ci.org/AndresMWeber/mayasig_cli.svg?branch=master 9 | :target: https://travis-ci.org/AndresMWeber/mayasig_cli 10 | 11 | .. image:: https://coveralls.io/repos/github/AndresMWeber/mayasig_cli/badge.svg?branch=master 12 | :target: https://coveralls.io/github/AndresMWeber/mayasig_cli?branch=master 13 | 14 | .. image:: https://landscape.io/github/AndresMWeber/maya-cmds-help/master/landscape.svg?style=flat 15 | :target: https://landscape.io/github/AndresMWeber/maya-cmds-help/master 16 | :alt: Code Health 17 | 18 | .. contents:: 19 | 20 | .. section-numbering:: 21 | 22 | Synopsis 23 | ============= 24 | 25 | If you're looking into this tool, you're looking for a programmatic way of getting Maya function signatures. The current version of the tool has unfiltered prints as status logs...so that might be a deterrent... I personally built it so that I could compare my maya command calls against kwargs/args Maya expects to reduce errors. 26 | 27 | Hope you'll find it useful! Once you install you will now have a CLI tool called mayasig. 28 | 29 | Features 30 | -------- 31 | - Caching 32 | - Up to date with online help docs 33 | - Temp file generator 34 | - JSON file output 35 | - CLI access 36 | - Dict output 37 | 38 | Installation 39 | ============ 40 | Windows, etc. 41 | ------------- 42 | A universal installation method (that works on Windows, Mac OS X, Linux, …, and always provides the latest version) is to use `pip`: 43 | 44 | .. code-block:: bash 45 | 46 | # Make sure we have an up-to-date version of pip and setuptools: 47 | $ pip install --upgrade pip setuptools 48 | $ pip install maya-cmds-help 49 | 50 | 51 | (If ``pip`` installation fails for some reason, you can try 52 | ``easy_install maya-cmds-help`` as a fallback.) 53 | 54 | Usage 55 | ============= 56 | 57 | Bash 58 | ------------ 59 | 60 | .. code-block:: bash 61 | 62 | mayasig 63 | 64 | Usage: 65 | mayasig [-m|--mayaversion VERSION] [-d|--depth DEPTH] (MAYA_CMDS ...) 66 | mayasig (-h|--help) 67 | mayasig (--version) 68 | 69 | Options: 70 | -h --help Show this screen. 71 | --version Show version. 72 | -m VERSION --mayaversion VERSION If you want to override which Maya docs we query (tested with 2015/2016/2017) [default: 2017] 73 | -d DEPTH --depth DEPTH The depth verbosity of the return dictionary [default: 1] 74 | MAYA_CMDS Maya commands to query/scrape from the help and return signatures for 75 | 76 | Examples: 77 | mayasig group 78 | 79 | Help: 80 | For help using this tool, please open an issue on the Github repository: 81 | https://github.com/andresmweber/mayasig-cli 82 | 83 | Python Package Usage 84 | --------------------- 85 | Feel free to access from the package instead via the two package-level convenience functions: 86 | 87 | .. code-block:: python 88 | 89 | maya_signatures.CACHE 90 | maya_signatures.query 91 | 92 | In order to access full functionality from the scraper class you can access a package level instance of maya_signatures.commands.scrape.Scraper using: 93 | 94 | .. code-block:: python 95 | 96 | maya_signatures.SCRAPER 97 | 98 | 99 | .. code-block:: python 100 | 101 | import maya_signatures 102 | maya_signatures.query('ls') 103 | # Result: 104 | # storing args ('ls',) storing kwargs {} 105 | # Successfully loaded json data, loading into cache... 106 | # Retrieving cached value for input http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/ls.html 107 | # wrote out tmp file C:\Users\andre\dev\maya_signature_builder\scrape.json 108 | 109 | maya_signatures.SCRAPER.build_command_stub('ls') 110 | # Result: def ls(*args, textures=bool, selection=bool, defaultNodes=bool, templated=bool, visible=bool, references=bool, flatten=bool, nodeTypes=bool, persistentNodes=bool, intermediateObjects=bool, long=bool, leaf=bool, recursive=bool, objectsOnly=bool, lockedNodes=bool, cameras=bool, tail=int, absoluteName=bool, lights=bool, live=bool, renderSetups=bool, containerType=str, preSelectHilite=bool, type=str, containers=bool, shortNames=bool, renderResolutions=bool, head=int, showType=bool, dependencyNodes=bool, orderedSelection=bool, renderQualities=bool, readOnly=bool, referencedNodes=bool, showNamespace=bool, invisible=bool, hilite=bool, untemplated=bool, partitions=bool, ghost=bool, uuid=bool, sets=bool, geometry=bool, assemblies=bool, noIntermediate=bool, modified=bool, allPaths=bool, shapes=bool, materials=bool, excludeType=str, planes=bool, exactType=str, renderGlobals=bool, undeletable=bool, dagObjects=bool, transforms=bool): 111 | # pass 112 | 113 | .. code-block:: python 114 | 115 | maya_signatures.query('group') 116 | # Result: storing args ('group',) storing kwargs {} 117 | # Successfully loaded json data, loading into cache... 118 | # Could not find key http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/group.html in cached values...retrieving... 119 | # Trying to find command for web page: 120 | # http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/group.html 121 | # wrote out tmp file C:\Users\andre\dev\maya_signature_builder\scrape.json 122 | maya_signatures.SCRAPER.get_command_flags('group') 123 | # Result: [('name', 'n'), ('parent', 'p'), ('relative', 'r'), ('useAsGroup', 'uag'), ('world', 'w'), ('empty', 'em'), ('absolute', 'a')] 124 | 125 | Class Documentation 126 | =================== 127 | .. automodule:: maya_signatures.commands.scrape 128 | :members: 129 | :undoc-members: 130 | :inherited-members: 131 | :show-inheritance: 132 | 133 | Version Support 134 | =============== 135 | This package supports the Maya 2015, 2016 and 2017 help docs so far so please be aware. 136 | I might back port a couple versions of the maya online help, but this is totally dependent on time. 137 | 138 | 139 | * :ref:`genindex` 140 | * :ref:`modindex` 141 | * :ref:`search` 142 | -------------------------------------------------------------------------------- /maya_signatures/__init__.py: -------------------------------------------------------------------------------- 1 | from . import commands 2 | from .commands.scrape import Scrape 3 | from . import version 4 | 5 | __version__ = version.__version__ 6 | __all__ = ['version', 'commands', 'cli'] 7 | 8 | CACHE = None 9 | SCRAPER = None 10 | 11 | 12 | def scrape(maya_commands): 13 | """ Generic entry point for ease of use, returns maya_signatures.commands.scrape.Scraper().query 14 | :param maya_commands: Commands to query and return 15 | :return: 16 | """ 17 | global SCRAPER 18 | global CACHE 19 | if SCRAPER is None: 20 | SCRAPER = Scrape() 21 | CACHE = SCRAPER.cached 22 | 23 | SCRAPER.query(maya_commands) 24 | -------------------------------------------------------------------------------- /maya_signatures/cli.py: -------------------------------------------------------------------------------- 1 | """ 2 | mayasig. 3 | 4 | Usage: 5 | mayasig [-m|--mayaversion VERSION] [-d|--depth DEPTH] (MAYA_CMDS ...) 6 | mayasig (-h|--help) 7 | mayasig (--version) 8 | 9 | Options: 10 | -h --help Show this screen. 11 | --version Show version. 12 | -m VERSION --mayaversion VERSION If you want to override which Maya docs we query (tested with 2015/2016/2017) [default: 2017] 13 | -d DEPTH --depth DEPTH The depth verbosity of the return dictionary [default: 1] 14 | MAYA_CMDS Maya commands to query/scrape from the help and return signatures for 15 | 16 | Examples: 17 | mayasig group 18 | 19 | Help: 20 | For help using this tool, please open an issue on the Github repository: 21 | https://github.com/andresmweber/mayasig-cli 22 | """ 23 | 24 | import commands as maya_signature_commands 25 | import docopt 26 | from pprint import pprint 27 | import sys 28 | from inspect import getmembers, isclass 29 | 30 | 31 | def main(): 32 | """Main CLI entry point.""" 33 | try: 34 | arguments = docopt.docopt(__doc__) 35 | except docopt.DocoptExit: 36 | print('invalid operation. %s' % str(sys.argv[1:])) 37 | raise 38 | 39 | has_run = False 40 | for command in list(arguments): 41 | if hasattr(maya_signature_commands, command): 42 | module = getattr(maya_signature_commands, command) 43 | commands = getmembers(module, isclass) 44 | command = [command[1] for command in commands if command[0] != 'Base'][0] 45 | command(arguments) 46 | has_run = True 47 | 48 | if not has_run: 49 | print('No command entered, defaulting to query mode for commands: %s' % ' '.join(arguments['MAYA_CMDS'])) 50 | pprint(maya_signature_commands.scrape.Scrape(arguments), depth=3) 51 | -------------------------------------------------------------------------------- /maya_signatures/commands/__init__.py: -------------------------------------------------------------------------------- 1 | from . import base 2 | from . import scrape 3 | 4 | __all__ = ['base', 'scrape'] 5 | -------------------------------------------------------------------------------- /maya_signatures/commands/base.py: -------------------------------------------------------------------------------- 1 | # maya_signatures/commands/base.py 2 | """The base structure for a CLI command.""" 3 | 4 | 5 | class Base(object): 6 | """A base command.""" 7 | 8 | def __init__(self, *args, **kwargs): 9 | if args: 10 | if isinstance(args[0], dict): 11 | kwargs = args[0] 12 | kwargs['MAYA_CMDS'] = args[1:] 13 | else: 14 | maya_commands = kwargs.get('MAYA_CMDS', list(args)) 15 | kwargs['MAYA_CMDS'] = maya_commands 16 | self.args = args 17 | self.kwargs = kwargs 18 | 19 | def run(self): 20 | raise NotImplementedError('You must implement the run() method yourself!') -------------------------------------------------------------------------------- /maya_signatures/commands/cache.py: -------------------------------------------------------------------------------- 1 | import inspect 2 | import functools 3 | 4 | 5 | class Memoize(object): 6 | """cache the return value of a method 7 | 8 | This class is meant to be used as a decorator of methods. The return value 9 | from a given method invocation will be cached on the instance whose method 10 | was invoked. All arguments passed to a method decorated with memoize must 11 | be hashable. 12 | 13 | If a memoized method is invoked directly on its class the result will not 14 | be cached. Instead the method will be invoked like a static method: 15 | class Obj(object): 16 | @memoize 17 | def add_to(self, arg): 18 | return self + arg 19 | Obj.add_to(1) # not enough arguments 20 | Obj.add_to(1, 2) # returns 3, result is not cached 21 | """ 22 | 23 | def __init__(self, func): 24 | self.func = func 25 | 26 | def __get__(self, obj, objtype=None): 27 | if obj is None: 28 | return self.func 29 | return functools.partial(self, obj) 30 | 31 | def __call__(self, *args, **kw): 32 | obj = args[0] 33 | try: 34 | cache = obj.__cache 35 | except AttributeError: 36 | cache = obj.__cache = {} 37 | key = (self.func, args[1:], frozenset(kw.items())) 38 | try: 39 | res = cache[key] 40 | except KeyError: 41 | res = cache[key] = self.func(*args, **kw) 42 | return res 43 | 44 | 45 | class KeyMemoized(object): 46 | """ Taken from 47 | http://stackoverflow.com/questions/10920180/is-there-a-pythonic-way-to-support-keyword-arguments-for-a-memoize-decorator-in 48 | http://stackoverflow.com/questions/4431703/python-resettable-instance-method-memoization-decorator 49 | Class is used as a decorator to memoize a given class' method to facilitate caching based on input etc. 50 | """ 51 | 52 | def __init__(self, func): 53 | self.func = func 54 | self.cache = {} 55 | 56 | def __call__(self, *args, **kwargs): 57 | key = self._key(args, kwargs) 58 | 59 | try: 60 | return self.cache[key] 61 | except KeyError: 62 | print('Could not find key %s in cached values...retrieving...' % key) 63 | value = self.func(*args) 64 | self.cache[key] = value 65 | return value 66 | except TypeError: 67 | # uncachable -- for instance, passing a list as an argument. 68 | # Better to not cache than to blow up entirely. 69 | return self.func(*args) 70 | 71 | def _normalize_args(self, args, kwargs): 72 | spec = inspect.getargs(self.func.__code__).args[1:] 73 | return dict(kwargs.items() + zip(spec, args)) 74 | 75 | @staticmethod 76 | def _key(args, kwargs): 77 | # a = self.normalize_args(args, kwargs) # useful for more intense scenarios. 78 | return ','.join(list(args) + list(kwargs)) 79 | 80 | def _reset(self): 81 | self.cache = {} 82 | 83 | def __repr__(self): 84 | """Return the function's docstring.""" 85 | return self.func.__doc__ 86 | 87 | def __get__(self, obj, objtype=None): 88 | if obj is None: 89 | return self.func 90 | return functools.partial(self, obj) 91 | -------------------------------------------------------------------------------- /maya_signatures/commands/scrape.py: -------------------------------------------------------------------------------- 1 | # maya_signatures/commands/scrape.py 2 | """The maya online help command signature scraping command.""" 3 | 4 | from six import iteritems 5 | import requests 6 | from re import findall 7 | import tempfile 8 | import json 9 | import shutil 10 | import os 11 | from .base import Base 12 | from .cache import Memoize 13 | from bs4 import BeautifulSoup 14 | 15 | 16 | class Scrape(Base): 17 | """ Class responsible for handling Maya help doc command queries and returns function signatures. 18 | 19 | """ 20 | BASEURL = 'http://help.autodesk.com/cloudhelp/{MAYAVERSION}/ENU/Maya-Tech-Docs/CommandsPython/' 21 | _EXTENSION = 'html' 22 | _URL_BUILDER = '{BASEURL}{COMMAND}.{EXT}' 23 | _CACHE_FILE = '%s.json' % __name__.split('.')[-1] 24 | __cache = {} 25 | 26 | def __init__(self, *args, **kwargs): 27 | super(Scrape, self).__init__(*args, **kwargs) 28 | self.depth = self.kwargs.get('--depth', 1) 29 | self.maya_version = self.kwargs.get('--mayaversion', ['2017'])[0] 30 | self.command_signatures = {} 31 | self.run() 32 | 33 | @property 34 | def cache_file(self): 35 | """ Provide the cache file path 36 | 37 | - **parameters**, **types**, **return**:: 38 | :return: str 39 | """ 40 | return os.path.join(os.getcwd(), self._CACHE_FILE) 41 | 42 | @property 43 | def cached(self): 44 | """ Provide the raw cache with urls as the dictionary keys 45 | 46 | - **parameters**, **types**, **return**:: 47 | :return: dict 48 | """ 49 | return self.__cache 50 | 51 | @property 52 | def stored_commands(self): 53 | """ Provide a list of commands that are currently stored. 54 | 55 | - **parameters**, **types**, **return**:: 56 | :return: list 57 | """ 58 | return list(self.command_signatures) 59 | 60 | def run(self): 61 | """ CLI interface command runner. 62 | 63 | - **parameters**, **types**, **return**:: 64 | :return: dict, command signatures dictionary sorted the commands as the keys 65 | """ 66 | self._read_tempfile() 67 | for command in self.kwargs.get('MAYA_CMDS', []): 68 | self.query(command) 69 | self._write_tempfile() 70 | return self.command_signatures 71 | 72 | def query(self, commands): 73 | """ Build URLs then stores all queried commands within the instance. 74 | :param commands: list(str) or str, valid maya command(s) 75 | :return: None 76 | """ 77 | if isinstance(commands, str): 78 | commands = [commands] 79 | 80 | for maya_command in commands: 81 | url = self._build_url(maya_command) 82 | self.command_signatures[maya_command] = self._scrape_command(url) 83 | 84 | def get_command_flags(self, command): 85 | """ Return only the flags for the given command. 86 | 87 | - **parameters**, **types**, **return**:: 88 | :param command: str, maya command 89 | :return: list(list(str, str)), list of lists of flags in format: [, ] 90 | """ 91 | return zip(list(self.command_signatures[command]), 92 | [self.command_signatures[command][flag]['short'] for flag in self.command_signatures[command]]) 93 | 94 | def build_command_stub(self, command, shortname=False, combined=False): 95 | """ Build a Python stub for the given command. 96 | 97 | - **parameters**, **types**, **return**:: 98 | :param command: str, valid maya command 99 | :param shortname: bool, whether or not we want to use the shortname of the flags 100 | :param combined: bool, whether we use both short name and long name of flags (will invalidate stub...) 101 | :return: str, Python formatted function stub for the given command 102 | """ 103 | lut = {'boolean': 'bool', 104 | 'string': 'str', 105 | 'int': 'int', 106 | 'timerange': 'int', 107 | 'floatrange': 'float', 108 | 'uint': 'int', 109 | 'angle': 'float', 110 | 'linear': 'float', 111 | 'float': 'float', 112 | } 113 | kwargs = [] 114 | shortname = False if combined else shortname 115 | docstring = '' 116 | 117 | for k, v in iteritems(self.command_signatures[command]): 118 | flag = k if not shortname else v['short'] 119 | 120 | if combined: 121 | flag += '(%s)' % v['short'] 122 | 123 | data_type = v['data_type'] 124 | find_types = findall('([a-z]+)', data_type) 125 | 126 | data_type = ', '.join([lut[ftype] + '()' for ftype in find_types]) 127 | if len(find_types) > 1: 128 | data_type = '[{TYPES}]'.format(TYPES=data_type) 129 | 130 | flag = '{FLAG}={TYPE}'.format(FLAG=flag, TYPE=data_type) 131 | docstring += '\n' + v['description'] 132 | kwargs.append(flag) 133 | 134 | signature = ', '.join(kwargs) 135 | command_line = 'def {CMD}({SIG}, *args):'.format(CMD=command, SIG=signature) 136 | docstring = '\"\"\"\n\t{DOC}\n\t\"\"\"'.format(DOC=docstring) 137 | body = 'pass' 138 | return '\n\t'.join([command_line, docstring, body]) 139 | 140 | def reset_cache(self): 141 | """ Clear the cache file of contents. 142 | 143 | - **parameters**, **types**, **return**:: 144 | :return: None 145 | """ 146 | open(self._CACHE_FILE, 'w').close() 147 | 148 | @Memoize 149 | def _scrape_command(self, maya_command_url): 150 | """ Actual worker command which parses the Maya online help docs for the given command URL. 151 | 152 | - **parameters**, **types**, **return**:: 153 | :return: dict(str:dict(str:str, str:str, str:str), dict with keys of flags and each flag value is a dict 154 | of short name 'short', data type 'data_type' and description 'description' 155 | """ 156 | print('Trying to find command for web page: \n\t%s' % maya_command_url) 157 | web_page_data = requests.get(maya_command_url) 158 | soup_data = BeautifulSoup(web_page_data.content, 'html.parser') 159 | 160 | raw_flag_table = self._parse_flag_table(soup_data) 161 | flags = self._compile_flag_table(raw_flag_table) 162 | return flags 163 | 164 | def _read_tempfile(self): 165 | """ Attempt to read and store instance data from the cache file. 166 | :return: None 167 | """ 168 | try: 169 | with open(self._CACHE_FILE, ) as data_file: 170 | try: 171 | data = json.load(data_file) 172 | except ValueError: 173 | data = {} 174 | print('Successfully loaded json data, loading into cache...') 175 | self.__cache = data 176 | except IOError: 177 | print('No preexisting scrape.json detected in folder %s continuing...' % self.cache_file) 178 | 179 | def _build_url(self, command): 180 | """ Use class variables to synthesize a URL path to the maya help lib for the given command. 181 | :param command: str, valid maya command 182 | :return: str, url to the maya help lib for given command. 183 | """ 184 | return self._URL_BUILDER.format(BASEURL=self.BASEURL.format(MAYAVERSION=self.maya_version), 185 | COMMAND=command, 186 | EXT=self._EXTENSION) 187 | 188 | def _write_tempfile(self): 189 | """ Writes instance data to the cache file. 190 | :return: None 191 | """ 192 | f = tempfile.NamedTemporaryFile(mode='w+t', delete=False) 193 | f.write(json.dumps(self.__cache, ensure_ascii=False, indent=4, sort_keys=True)) 194 | file_name = f.name 195 | f.close() 196 | shutil.copy(file_name, self._CACHE_FILE) 197 | print("wrote out tmp file %s" % self.cache_file) 198 | 199 | @classmethod 200 | def _parse_synopsis(cls, soup_code_object): 201 | """ Parse the webpage for the synopsis value. 202 | :param soup_code_object: str, return of beautiful soup for maya help doc page 203 | :return: list(str): list of synopsis values (should be the flags) 204 | """ 205 | synopses = [] 206 | for child in [child for child in soup_code_object.children]: 207 | synopses.append(str(child) if not hasattr(child, 'string') else child.string) 208 | return synopses 209 | 210 | @classmethod 211 | def _parse_flag_table(cls, soup_code_object): 212 | """ Parse (naively) the webpage for the flag table. 213 | :param soup_code_object: str, return of beautiful soup for maya help doc page 214 | :return: list(list(str, str, str, str)): list of lists len 4 of: 215 | flag name, short name, data type, description 216 | """ 217 | signature_table = [table for table in soup_code_object.body.find_all('table') 218 | if 'Long name (short name)' in str(table.find_all('tr'))][0] 219 | 220 | data = [] 221 | for table_row in signature_table.find_all('td'): 222 | # This is a ghetto way of checking whether it's the right row we want...but it works. 223 | if table_row.attrs.get('colspan') is None: 224 | text = str(table_row.text.strip()).replace('\n', ' ') 225 | # Might need refactoring later depending on how they format their flags/descriptions, but we'll see 226 | if len(text.split('(')) == 2 and not ' ' in text: 227 | text = [t.replace(')', '') for t in text.split('(')] 228 | data += text 229 | elif text: 230 | data.append(text) 231 | 232 | return [data[x:x + 4] for x in range(0, len(data), 4)] 233 | 234 | @staticmethod 235 | def _compile_flag_table(flag_data_set): 236 | """ Take the parsed data set from Scrape.parse_flag_table and creates a dictionary. 237 | :param flag_data_set: list(list(str, str, str, str)): list of lists len 4 of: 238 | flag name, short name, data type, description 239 | :return: dict(str:dict(str:str, str:str, str:str), dict with keys of flags and each flag value is a dict 240 | of short name 'short', data type 'data_type' and description 'description' 241 | """ 242 | flags = {} 243 | for flag_data in flag_data_set: 244 | name, short, data_type, description = flag_data 245 | flags[name] = {'short': short, 'data_type': data_type, 'description': description} 246 | 247 | return flags 248 | -------------------------------------------------------------------------------- /maya_signatures/version.py: -------------------------------------------------------------------------------- 1 | __version__ = '0.6.6' 2 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.5.3 2 | coverage==4.3.4 3 | docutils==0.13.1 4 | nose==1.3.7 5 | packaging==16.8 6 | py==1.4.33 7 | requests==2.13.0 8 | six==1.10.0 9 | Sphinx==1.5.5 10 | tox==2.7.0 11 | twine==1.8.1 12 | virtualenv==15.1.0 13 | docopt==0.6.2 14 | -------------------------------------------------------------------------------- /scrape.json: -------------------------------------------------------------------------------- 1 | { 2 | "http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/group.html": { 3 | "absolute": { 4 | "data_type": "boolean", 5 | "description": "preserve existing world object transformations (overall object transformation is preserved by modifying the objects local transformation) [default]", 6 | "short": "a" 7 | }, 8 | "empty": { 9 | "data_type": "boolean", 10 | "description": "create an empty group (with no objects in it)", 11 | "short": "em" 12 | }, 13 | "name": { 14 | "data_type": "string", 15 | "description": "Assign given name to new group node.", 16 | "short": "n" 17 | }, 18 | "parent": { 19 | "data_type": "string", 20 | "description": "put the new group under the given parent", 21 | "short": "p" 22 | }, 23 | "relative": { 24 | "data_type": "boolean", 25 | "description": "preserve existing local object transformations (relative to the new group node)", 26 | "short": "r" 27 | }, 28 | "useAsGroup": { 29 | "data_type": "string", 30 | "description": "Use the specified node as the group node. The specified node must be derived from the transform node and must not have any existing parents or children.", 31 | "short": "uag" 32 | }, 33 | "world": { 34 | "data_type": "boolean", 35 | "description": "put the new group under the world", 36 | "short": "w" 37 | } 38 | }, 39 | "http://help.autodesk.com/cloudhelp/2017/ENU/Maya-Tech-Docs/CommandsPython/ls.html": { 40 | "absoluteName": { 41 | "data_type": "boolean", 42 | "description": "This flag can be used in conjunction with the showNamespace flag to specify that the namespace(s) returned by the command be in absolute namespace format. The absolute name of the namespace is a full namespace path, starting from the root namespace \":\" and including all parent namespaces. For example \":ns:ball\" is an absolute namespace name while \"ns:ball\" is not. The absolute namespace name is invariant and is not affected by the current namespace or relative namespace modes.", 43 | "short": "an" 44 | }, 45 | "allPaths": { 46 | "data_type": "boolean", 47 | "description": "List all paths to nodes in DAG. This flag only works if -dag is also specified or if an object name is supplied.", 48 | "short": "ap" 49 | }, 50 | "assemblies": { 51 | "data_type": "boolean", 52 | "description": "List top level transform Dag objects", 53 | "short": "assemblies" 54 | }, 55 | "cameras": { 56 | "data_type": "boolean", 57 | "description": "List camera shapes.", 58 | "short": "ca" 59 | }, 60 | "containerType": { 61 | "data_type": "string", 62 | "description": "List containers with the specified user-defined type. This flag cannot be used in conjunction with the type or exactType flag.", 63 | "short": "ct" 64 | }, 65 | "containers": { 66 | "data_type": "boolean", 67 | "description": "List containers. Includes both standard containers as well as other types of containers such as dagContainers.", 68 | "short": "con" 69 | }, 70 | "dagObjects": { 71 | "data_type": "boolean", 72 | "description": "List Dag objects of any type. If object name arguments are passed to the command then this flag will list all Dag objects below the specified object(s).", 73 | "short": "dag" 74 | }, 75 | "defaultNodes": { 76 | "data_type": "boolean", 77 | "description": "Returns default nodes. A default node is one that Maya creates automatically and does not get saved out with the scene, although some of its attribute values may.", 78 | "short": "dn" 79 | }, 80 | "dependencyNodes": { 81 | "data_type": "boolean", 82 | "description": "List dependency nodes. (including Dag objects)", 83 | "short": "dep" 84 | }, 85 | "exactType": { 86 | "data_type": "string", 87 | "description": "List all objects of the specified type, but not objects that are descendents of that type. This flag can appear multiple times on the command line. Note: the type passed to this flag is the same type name returned from the showType flag. This flag cannot be used in conjunction with the type or excludeType flag.", 88 | "short": "et" 89 | }, 90 | "excludeType": { 91 | "data_type": "string", 92 | "description": "List all objects that are not of the specified type. This flag can appear multiple times on the command line. Note: the type passed to this flag is the same type name returned from the showType flag. This flag cannot be used in conjunction with the type or exactType flag.", 93 | "short": "ext" 94 | }, 95 | "flatten": { 96 | "data_type": "boolean", 97 | "description": "Flattens the returned list of objects so that each component is identified individually.", 98 | "short": "fl" 99 | }, 100 | "geometry": { 101 | "data_type": "boolean", 102 | "description": "List geometric Dag objects.", 103 | "short": "g" 104 | }, 105 | "ghost": { 106 | "data_type": "boolean", 107 | "description": "List ghosting objects.", 108 | "short": "gh" 109 | }, 110 | "head": { 111 | "data_type": "int", 112 | "description": "This flag specifies the maximum number of elements to be returned from the beginning of the list of items. Note: each type flag will return at most this many items so if multiple type flags are specified then the number of items returned can be greater than this amount.", 113 | "short": "hd" 114 | }, 115 | "hilite": { 116 | "data_type": "boolean", 117 | "description": "List objects that are currently hilited for component selection.", 118 | "short": "hl" 119 | }, 120 | "intermediateObjects": { 121 | "data_type": "boolean", 122 | "description": "List only intermediate dag nodes.", 123 | "short": "io" 124 | }, 125 | "invisible": { 126 | "data_type": "boolean", 127 | "description": "List only invisible dag nodes.", 128 | "short": "iv" 129 | }, 130 | "leaf": { 131 | "data_type": "boolean", 132 | "description": "List all leaf nodes in Dag. This flag is a modifier and must be used in conjunction with the -dag flag.", 133 | "short": "lf" 134 | }, 135 | "lights": { 136 | "data_type": "boolean", 137 | "description": "List light shapes.", 138 | "short": "lt" 139 | }, 140 | "live": { 141 | "data_type": "boolean", 142 | "description": "List objects that are currently live.", 143 | "short": "lv" 144 | }, 145 | "lockedNodes": { 146 | "data_type": "boolean", 147 | "description": "Returns locked nodes, which cannot be deleted or renamed. However, their status may change.", 148 | "short": "ln" 149 | }, 150 | "long": { 151 | "data_type": "boolean", 152 | "description": "Return full path names for Dag objects. By default the shortest unique name is returned.", 153 | "short": "l" 154 | }, 155 | "materials": { 156 | "data_type": "boolean", 157 | "description": "List materials or shading groups.", 158 | "short": "mat" 159 | }, 160 | "modified": { 161 | "data_type": "boolean", 162 | "description": "When this flag is set, only nodes modified since the last save will be returned.", 163 | "short": "mod" 164 | }, 165 | "noIntermediate": { 166 | "data_type": "boolean", 167 | "description": "List only non intermediate dag nodes.", 168 | "short": "ni" 169 | }, 170 | "nodeTypes": { 171 | "data_type": "boolean", 172 | "description": "Lists all registered node types.", 173 | "short": "nt" 174 | }, 175 | "objectsOnly": { 176 | "data_type": "boolean", 177 | "description": "When this flag is set only object names will be returned and components/attributes will be ignored.", 178 | "short": "o" 179 | }, 180 | "orderedSelection": { 181 | "data_type": "boolean", 182 | "description": "List objects and components that are currently selected in their order of selection. This flag depends on the value of the -tso/trackSelectionOrder flag of the selectPref command. If that flag is not enabled than this flag will return the same thing as the -sl/selection flag would.", 183 | "short": "os" 184 | }, 185 | "partitions": { 186 | "data_type": "boolean", 187 | "description": "List partitions.", 188 | "short": "pr" 189 | }, 190 | "persistentNodes": { 191 | "data_type": "boolean", 192 | "description": "Returns persistent nodes, which are nodes that stay in the Maya session after a file > new. These are a special class of default nodes that do not get reset on file > new. Ex: itemFilter and selectionListOperator nodes.", 193 | "short": "pn" 194 | }, 195 | "planes": { 196 | "data_type": "boolean", 197 | "description": "List construction plane shapes.", 198 | "short": "pl" 199 | }, 200 | "preSelectHilite": { 201 | "data_type": "boolean", 202 | "description": "List components that are currently hilited for pre-selection.", 203 | "short": "psh" 204 | }, 205 | "readOnly": { 206 | "data_type": "boolean", 207 | "description": "Returns referenced nodes. Referenced nodes are read only. NOTE: Obsolete. Please use \"-referencedNodes\".", 208 | "short": "ro" 209 | }, 210 | "recursive": { 211 | "data_type": "boolean", 212 | "description": "When set to true, this command will look for name matches in all namespaces. When set to false, this command will only look for matches in namespaces that are requested (e.g. by specifying a name containing the ':'... \"ns1:pSphere1\").", 213 | "short": "r" 214 | }, 215 | "referencedNodes": { 216 | "data_type": "boolean", 217 | "description": "Returns referenced nodes. Referenced nodes are read only.", 218 | "short": "rn" 219 | }, 220 | "references": { 221 | "data_type": "boolean", 222 | "description": "List references associated with files. Excludes special reference nodes such as the sharedReferenceNode and unknown reference nodes.", 223 | "short": "rf" 224 | }, 225 | "renderGlobals": { 226 | "data_type": "boolean", 227 | "description": "List render globals.", 228 | "short": "rg" 229 | }, 230 | "renderQualities": { 231 | "data_type": "boolean", 232 | "description": "List named render qualities.", 233 | "short": "rq" 234 | }, 235 | "renderResolutions": { 236 | "data_type": "boolean", 237 | "description": "List render resolutions.", 238 | "short": "rr" 239 | }, 240 | "renderSetups": { 241 | "data_type": "boolean", 242 | "description": "Alias for -renderGlobals.", 243 | "short": "rs" 244 | }, 245 | "selection": { 246 | "data_type": "boolean", 247 | "description": "List objects that are currently selected.", 248 | "short": "sl" 249 | }, 250 | "sets": { 251 | "data_type": "boolean", 252 | "description": "List sets.", 253 | "short": "set" 254 | }, 255 | "shapes": { 256 | "data_type": "boolean", 257 | "description": "List shape objects.", 258 | "short": "s" 259 | }, 260 | "shortNames": { 261 | "data_type": "boolean", 262 | "description": "Return short attribute names. By default long attribute names are returned.", 263 | "short": "sn" 264 | }, 265 | "showNamespace": { 266 | "data_type": "boolean", 267 | "description": "Show the namespace of each object after the object name. This flag cannot be used in conjunction with the showType flag.", 268 | "short": "sns" 269 | }, 270 | "showType": { 271 | "data_type": "boolean", 272 | "description": "List the type of each object after its name.", 273 | "short": "st" 274 | }, 275 | "tail": { 276 | "data_type": "int", 277 | "description": "This flag specifies the maximum number of elements to be returned from the end of the list of items. Note: each type flag will return at most this many items so if multiple type flags are specified then the number of items returned can be greater than this amount", 278 | "short": "tl" 279 | }, 280 | "templated": { 281 | "data_type": "boolean", 282 | "description": "List only templated dag nodes.", 283 | "short": "tm" 284 | }, 285 | "textures": { 286 | "data_type": "boolean", 287 | "description": "List textures.", 288 | "short": "tex" 289 | }, 290 | "transforms": { 291 | "data_type": "boolean", 292 | "description": "List transform objects.", 293 | "short": "tr" 294 | }, 295 | "type": { 296 | "data_type": "string", 297 | "description": "List all objects of the specified type. This flag can appear multiple times on the command line. Note: the type passed to this flag is the same type name returned from the showType flag. Note: some selection items in Maya do not have a specific object/data type associated with them and will return \"untyped\" when listed with this flag. This flag cannot be used in conjunction with the exactType or excludeType flag.", 298 | "short": "typ" 299 | }, 300 | "undeletable": { 301 | "data_type": "boolean", 302 | "description": "Returns nodes that cannot be deleted (which includes locked nodes). These nodes also cannot be renamed.", 303 | "short": "ud" 304 | }, 305 | "untemplated": { 306 | "data_type": "boolean", 307 | "description": "List only un-templated dag nodes.", 308 | "short": "ut" 309 | }, 310 | "uuid": { 311 | "data_type": "boolean", 312 | "description": "Return node UUIDs instead of names. Note that there are no \"UUID paths\" - combining this flag with e.g. the -long flag will not result in a path formed of node UUIDs.", 313 | "short": "uid" 314 | }, 315 | "visible": { 316 | "data_type": "boolean", 317 | "description": "List only visible dag nodes.", 318 | "short": "v" 319 | } 320 | } 321 | } -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | # setup.cfg 2 | [bdist_wheel] 3 | universal=1 -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """Packaging settings.""" 2 | import codecs 3 | from os.path import abspath, dirname, join 4 | from setuptools import setup, find_packages 5 | from distutils.util import convert_path 6 | 7 | __package__ = 'maya_signatures' 8 | 9 | # from: 10 | # http://stackoverflow.com/questions/2058802/how-can-i-get-the-version-defined-in-setup-py-setuptools-in-my-package 11 | main_ns = {} 12 | with open(convert_path('%s/version.py' % __package__)) as ver_file: 13 | exec (ver_file.read(), main_ns) 14 | 15 | with codecs.open(join(abspath(dirname(__file__)), 'README.rst'), encoding='utf-8') as readme_file: 16 | long_description = readme_file.read() 17 | 18 | setup( 19 | name='maya-cmds-help', 20 | version=main_ns['__version__'], 21 | description=("A module and command line tool that scrapes the online maya help docs to query an input " 22 | "maya.cmds command (or build stubs) for its signature in Python."), 23 | long_description=long_description, 24 | url='https://github.com/andresmweber/maya-cmds-help.git', 25 | author='Andres Weber', 26 | author_email='andresmweber@gmail.com', 27 | license='MIT', 28 | classifiers=[ 29 | 'Intended Audience :: Developers', 30 | 'Topic :: Utilities', 31 | 'License :: Public Domain', 32 | 'Natural Language :: English', 33 | 'Operating System :: OS Independent', 34 | 'Programming Language :: Python :: 3', 35 | ], 36 | keywords=['cli', 'maya', 'stubs', 'stub', 'commands', 'maya.cmds', 'autodesk'], 37 | packages=find_packages(exclude=['docs', 'tests*']), 38 | install_requires=['redis', 'bs4', 'requests', 'six'], 39 | extras_require={ 40 | 'test': ['coverage', 'nose', 'tox', 'virtualenv', 'travis', 'python-coveralls'], 41 | 'dev': ['distutils2', 'twine', 'virtualenv', 'Sphinx', 'docutils', 'docopt'] 42 | }, 43 | entry_points={ 44 | 'console_scripts': [ 45 | 'mayasig=maya_signatures.cli:main', 46 | ], 47 | }, 48 | cmdclass={'test': 'tox'}, 49 | ) 50 | -------------------------------------------------------------------------------- /tests/test_scrape.py: -------------------------------------------------------------------------------- 1 | import maya_signatures.commands.scrape as scrape 2 | import unittest 3 | import os 4 | 5 | 6 | class TestBase(unittest.TestCase): 7 | def setUp(self): 8 | super(TestBase, self).setUp() 9 | self.scraper = scrape.Scrape() 10 | 11 | 12 | class TestScrape(TestBase): 13 | def test_instantiation(self): 14 | scrape.Scrape() 15 | 16 | def test_instantiation_with_command(self): 17 | scraper = scrape.Scrape('ls') 18 | self.assertEquals(scraper.stored_commands, ['ls']) 19 | 20 | def test_stored_commands(self): 21 | self.scraper.query('ls') 22 | self.assertEquals(self.scraper.stored_commands, ['ls']) 23 | 24 | def test_instantiation_with_commands(self): 25 | scraper = scrape.Scrape(['ls', 'group']) 26 | self.assertEquals(sorted(scraper.stored_commands), sorted(['ls', 'group'])) 27 | 28 | def test_instantiation_with_command_and_run(self): 29 | scraper = scrape.Scrape('ls') 30 | scraper.run() 31 | self.assertEquals(scraper.stored_commands, ['ls']) 32 | 33 | def testquery_single(self): 34 | self.assertIsNone(self.scraper.query('joint')) 35 | 36 | def testquery_multiple(self): 37 | self.assertIsNone(self.scraper.query(['joint', 'group'])) 38 | 39 | def test_reset_cache(self): 40 | scraper = scrape.Scrape('group') 41 | scraper.reset_cache() 42 | self.assertEquals(scraper.cached, {}) 43 | 44 | def test_get_command_flags(self): 45 | self.scraper.query('group') 46 | self.scraper.get_command_flags('group') 47 | 48 | def test_build_command_stub(self): 49 | self.scraper.query('joint') 50 | stub = self.scraper.build_command_stub('joint') 51 | exec(compile(stub, '', 'exec')) 52 | self.assertIn('joint', locals()) 53 | 54 | def test_build_command_stub_shortname(self): 55 | self.scraper.query('joint') 56 | stub = self.scraper.build_command_stub('joint', shortname=True) 57 | exec(compile(stub, '', 'exec')) 58 | self.assertIn('joint', locals()) 59 | 60 | def test_build_command_stub_combined(self): 61 | self.scraper.query('joint') 62 | self.scraper.build_command_stub('joint', combined=True) 63 | 64 | def test_cache_file(self): 65 | self.scraper.query('joint') 66 | self.assertTrue(os.path.isfile(self.scraper.cache_file)) 67 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (https://tox.readthedocs.io/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py27, py36 8 | skip_missing_interpreters = true 9 | 10 | [testenv] 11 | passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH 12 | deps = 13 | coveralls 14 | -rrequirements.txt 15 | install_command = pip install -U --pre {opts} {packages} 16 | changedir = {envdir} 17 | commands = 18 | nosetests --with-coverage --cover-package=maya_signatures {toxinidir} 19 | - coveralls 20 | --------------------------------------------------------------------------------