├── .gitignore ├── README.txt ├── pycharm-3.4-screenshot.png ├── python_api └── pypredef_gen.py └── refresh_python_api /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .idea 3 | python_api/pypredef-tmp 4 | python_api/pypredef 5 | -------------------------------------------------------------------------------- /README.txt: -------------------------------------------------------------------------------- 1 | This project includes a script that uses reflection to extract 2 | blender's python API from a running instance of blender and store it 3 | in .py files usable by the pycharm IDE to aid in code completion. 4 | 5 | This source code is derived from pydev-blender.zip at 6 | http://airplanes3d.net/pydev-000_e.xml 7 | 8 | First: generate a fresh set of skeletons using ./refresh_python_api 9 | (which simply invokes python_api/pypredef_gen.py inside blender) 10 | 11 | Then you can add the python_api/pypredef directory to pycharm's 12 | interpreter using the screenshot pycharm-3.4-screenshot.png and the 13 | instructions at http://stackoverflow.com/a/24206781/995935 14 | 15 | If you do not want to add the blender API stubs to all your pycharm 16 | projects you can simply add the python_api/pypredef directory to your 17 | Project Structure. 18 | 19 | https://www.blender.org/download/ 20 | 21 | https://www.jetbrains.com/pycharm/ 22 | -------------------------------------------------------------------------------- /pycharm-3.4-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mutantbob/pycharm-blender/4aefa6ca8ccfe43dbd1fdbfdd176ba462b759167/pycharm-3.4-screenshot.png -------------------------------------------------------------------------------- /python_api/pypredef_gen.py: -------------------------------------------------------------------------------- 1 | # ***** BEGIN GPL LICENSE BLOCK ***** 2 | # 3 | # This program is free software; you can redistribute it and/or 4 | # modify it under the terms of the GNU General Public License 5 | # as published by the Free Software Foundation; either version 2 6 | # of the License, or (at your option) any later version. 7 | # 8 | # This program is distributed in the hope that it will be useful, 9 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | # GNU General Public License for more details. 12 | # 13 | # You should have received a copy of the GNU General Public License 14 | # along with this program; if not, write to the Free Software Foundation, 15 | # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 16 | # 17 | # Contributor(s): Campbell Barton, Witold Jaworski 18 | # ***** End GPL LICENSE BLOCK ***** 19 | ''' 20 | Creates Python predefinition (*.pypredef) files for Blender API 21 | The *.pypredef files are useful for syntax checking and 22 | auto-completion of expressions in Eclipse IDE (with PyDev plugin) 23 | 24 | This program is based on Campbell Barton's sphinx_doc_gen.py script 25 | 26 | @author: Witold Jaworski (http://www.airplanes3d.net) 27 | ''' 28 | #FIXES/UPDATES: 29 | #2012-03-01: In Blender 2.62 the description of the @roll argument in EditBone.transform() 30 | # method has an unexpected empty line, which break processing. Added handling 31 | # for that case in process_line() method 32 | #2013-03-01: In Blender 2.66 two methods of the bpy.types.Space obejects are reported as 33 | # Python - implemented methods, while tehy are not: 34 | # draw_handler_add() and draw_handler_remove() 35 | # I have added additional try.. except caluse to hande such errors in the future 36 | # (However, as long as the descriptions of these methods are wrong, tehy are not documented) 37 | #2013-03-13: Updates by Brian Henke: 38 | # * add a no-op (pass) to functions; most were passing because they have comments but the parser fails when there are none. 39 | # * Remove the "import" class because it is a reserved keyword. 40 | #2013-03-14: Further updates: I have found another function (py_c_func2predef()) which was ommited in 41 | # the Brian update. I added the "pass" statement generation there. 42 | 43 | #2016-June: modifications by Robert Forsman for use with pycharm 44 | script_help_msg = ''' 45 | Usage: 46 | - Run this script from blenders root path: 47 | 48 | .\blender.exe -b -P doc\python_api\pypredef_gen.py 49 | 50 | This will generate PyDev python predefiniton files (for Eclipse) in doc\python_api\pypredef\, 51 | assuming that .\blender.exe is the blender executable, and you have placed this script in 52 | .\doc\python_api\ Blender's subdirectory. 53 | ''' 54 | 55 | ''' 56 | Comments to using the pypredef files in Eclipse: 57 | 1. Add the directory that contains the *.pypredef files to PYTHONPATH of your project: 58 | - Open Project-->Properties window. 59 | - Select PyDev - PYTHONPATH option. 60 | - In External Libraries tab add this directory to the list. 61 | 2. In the same tab (External Libraries) press the button [Force restore internal info] 62 | 63 | NOTE: The completion may sometimes appear after a 1-2s. delay. 64 | When you type "." it doesn't, But when you remove it, and type again ".", it appears! 65 | 66 | NOTE: In case of specific bpy.app submodule, use it in your code in the following way: 67 | 68 | from bpy import app 69 | c = app.build_time 70 | 71 | (because plain "import bpy.app" does not work)! 72 | ''' 73 | 74 | import sys 75 | 76 | # Switch for quick testing 77 | # select modules to build: 78 | INCLUDE_MODULES = ( 79 | "bpy", 80 | "bpy.app", 81 | "bpy.path", 82 | "bpy.props", 83 | "bpy.utils", 84 | "bmesh", 85 | "bmesh.types", 86 | "bge", 87 | "aud", 88 | "bgl", 89 | "blf", 90 | "mathutils", 91 | "mathutils.geometry" 92 | ) 93 | 94 | _BPY_STRUCT_FAKE = "bpy_struct" 95 | _BPY_FULL_REBUILD = False 96 | _IDENT = " " 97 | 98 | #dictionary, used to correct some type descriptions: 99 | TYPE_ABERRATIONS = { 100 | "boolean" : "bool", 101 | "integer" : "int", 102 | "enum" : "str", 103 | "string" : "str", 104 | "Matrix" : "mathutils.Matrix", 105 | "Vector" : "mathutils.Vector", 106 | "Quaternion": "mathutils.Quaternion", 107 | "Color" : "mathutils.Color", 108 | "Euler" : "mathutils.Euler", 109 | "subclass of bpy_struct" : "bpy_struct", 110 | "subclass of bpy.types.bpy_struct" : "bpy_struct", 111 | "bpy.types.FCurve or list if index is -1 with an array property." : "bpy.types.FCurve", 112 | "float triplet": "(float, float, float)", 113 | "string in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']" : "str #in ['XYZ', 'XZY', 'YXZ', 'YZX', 'ZXY', 'ZYX']", 114 | "tuple of 2 floats":"(float, float)", 115 | "mathutils.Vector's" : "mathutils.Vector", 116 | "list of mathutils.Vector's":"[mathutils.Vector]", 117 | "tuple, pair of floats":"(float, float)", 118 | "tuple of mathutils.Vector's":"(mathutils.Vector, mathutils.Vector)", 119 | "mathutils.Vector or None":"mathutils.Vector", 120 | "list of strigs":"[str]", 121 | "list of strings":"[str]", 122 | "FCurve or list if index is -1 with an array property":"FCurve", 123 | "list of key, value tuples": ("[(str, types.%s)]" % _BPY_STRUCT_FAKE) 124 | } 125 | 126 | import os 127 | import sys 128 | import inspect 129 | import types 130 | import bpy 131 | import rna_info 132 | 133 | #---- learning types "by example" 134 | # lame, the standard types modelule does not contains many type classes 135 | # so we have to define it "by example": 136 | class _example: 137 | @property 138 | def a_property(self): 139 | return None 140 | 141 | @classmethod 142 | def a_classmethod(cls): 143 | return None 144 | 145 | @staticmethod 146 | def a_staticmethod(): 147 | return None 148 | 149 | PropertyType = type(_example.a_property) 150 | ClassMethodType = type(_example.__dict__["a_classmethod"]) 151 | StaticMethodType = type(_example.__dict__["a_staticmethod"]) 152 | ClassMethodDescriptorType = type(dict.__dict__['fromkeys']) 153 | MethodDescriptorType = type(dict.get) 154 | GetSetDescriptorType = type(int.real) 155 | #---- end "learning by example" 156 | 157 | def write_indented_lines(ident, fn, text, strip=True): 158 | ''' Helper function. Apply same indentation to all lines in a multilines text. 159 | Details: 160 | @ident (string): the required prefix (spaces) 161 | @fn (function): the print() or file.write() function 162 | @text (string): the lines that have to be shifted right 163 | @strip (boolean): True, when the lines should be stripped 164 | from leading and trailing spaces 165 | ''' 166 | if text is None: 167 | return 168 | for l in text.split("\n"): 169 | if strip: 170 | fn(ident + l.strip() + "\n") 171 | else: 172 | fn(ident + l + "\n") 173 | 174 | #Helper functions, that transforms the RST doctext like this: 175 | # .. method:: from_pydata(vertices, edges, faces) 176 | # 177 | # Make a mesh from a list of verts/edges/faces 178 | # Until we have a nicer way to make geometry, use this. 179 | # 180 | # :arg vertices: float triplets each representing (X, Y, Z) eg: [(0.0, 1.0, 0.5), ...]. 181 | # :type vertices: iterable object 182 | # :arg edges: int pairs, each pair contains two indices to the *vertices* argument. eg: [(1, 2), ...] 183 | # :type edges: iterable object 184 | # :arg faces: iterator of faces, each faces contains three or four indices to the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...] 185 | # :type faces: iterable object 186 | # 187 | #into pypredef header definition list, which contains following text: 188 | # 189 | # def from_pydata(vertices, edges, faces): 190 | # ''' Make a mesh from a list of verts/edges/faces 191 | # Until we have a nicer way to make geometry, use this. 192 | # Arguments: 193 | # @vertices (iterable object): float triplets each representing (X, Y, Z) eg: [(0.0, 1.0, 0.5), ...]. 194 | # @edges (iterable object): int pairs, each pair contains two indices to the *vertices* argument. eg: [(1, 2), ...] 195 | # @faces (iterable object): iterator of faces, each faces contains three or four indices to the *vertices* argument. eg: [(5, 6, 8, 9), (1, 2, 3), ...] 196 | # ''' 197 | #Some blender built-in functions have nothing, but such formatted docstring (in bpy.props, for example) 198 | def rst2list(doc): 199 | '''Method tries convert given doctext into list of definition elements 200 | Arguments: 201 | @doc (string) - the documentation text of the member (preferably in sphinx RST syntax) 202 | Returns: dictionary with identified elements of the definition (keys: "@def","@description","@returns", and zero or more function arguments) 203 | each dictionary item is a small dictionary, which content depends on the keyword: 204 | "@def": 205 | "prototype" : function declaration - "([`" 254 | # with "" 255 | line = line.replace(":exc:","").replace("`","") #replace occurences of ":exc:``" 256 | # with "" 257 | if line.startswith(".. method::") or line.startswith(".. function::") or line.startswith(".. classmethod::"): 258 | prototype = (line.split("::",1)[1]).lstrip(" ") 259 | last_entry = "@def" 260 | definition["@def"].setdefault("prototype",prototype) 261 | elif line.startswith(":arg"): 262 | expr = line.split(" ",2) 263 | name = expr[1].rstrip(":") 264 | if len(expr) == 3: 265 | definition.setdefault(name,{"name":name, "description":expr[2], "ord":len(definition)}) 266 | else: 267 | definition.setdefault(name,{"name":name, "description":"", "ord":len(definition)}) 268 | last_entry = name 269 | elif line.startswith(":type:"): #property type 270 | expr = type_name(line) 271 | if expr: definition["@def"].setdefault("type",expr) 272 | last_entry = "@def" 273 | elif line.startswith(":return:"): #return description 274 | expr = line.split(" ",1) 275 | name = "@returns" 276 | definition.setdefault(name,{"name": "returns", "description":expr[1], "ord":len(definition)}) 277 | last_entry = name 278 | elif line.startswith(":rtype:"): #type, returned by the function 279 | expr = type_name(line) 280 | if last_entry != "@returns": last_entry = "@def" 281 | if expr: definition[last_entry].setdefault("type",expr) 282 | elif line.startswith(":type"): #argument's type 283 | expr = line.split(" ",2) 284 | name = expr[1].rstrip(":") 285 | try: 286 | definition[name].setdefault("type",expr[2]) 287 | last_entry = name 288 | except: 289 | print("Missing argument declaration for '%s'" % name) 290 | elif line.startswith(".. note:: "): #note to member description 291 | line = line.replace(".. note:: ","") 292 | name = "@note" 293 | definition.setdefault(name,{"description":line, "ord":len(definition)}) 294 | last_entry = name 295 | elif line.startswith(".. seealso::"): #reference to external resource 296 | line = line.replace(".. seealso:: ","") 297 | name = "@seealso" 298 | definition.setdefault(name,{"description":line, "ord":len(definition)}) 299 | last_entry = name 300 | elif line.startswith(".. literalinclude::"): 301 | pass #skip this line 302 | else: #this is just second line of description for the last entry 303 | # (whole member, or just an single argument) 304 | if last_entry in definition and line != "" and not line.startswith("Undocumented"): 305 | item = definition[last_entry] 306 | if "description" not in item: 307 | item.setdefault("description",line) 308 | else: 309 | item["description"] = item["description"] + line + "\n" 310 | return last_entry 311 | #--------------------------------- process_line 312 | lines = doc.split("\n") 313 | last_key = "@def" 314 | definition = {last_key:{"description":"", "ord":0}} #at the beginning: empty description of function definition 315 | 316 | for line in lines: 317 | last_key = process_line(line,definition,last_key) 318 | #now let's check the result, stored in dictionary: 319 | return definition 320 | 321 | def get_item(dictionary,key): 322 | '''Helper function. Returns the dictionary element at key, or None 323 | Arguments: 324 | @dictionary: the dictionary which will be searched 325 | @key: the key in the dictionary 326 | ''' 327 | if key in dictionary: 328 | return dictionary[key] 329 | else: 330 | return None 331 | 332 | def rna2list(info): 333 | ''' Prepares list of definition elements 334 | Arguments: 335 | @info (one of rna_info.Info*RNA types) - the descriptor of Struct, Operator, Function or Property 336 | Returns: dictionary of the same structure, like the one returned by rst2list() 337 | "@def": 338 | "prototype" : used in structs and functions 339 | for struct: declaration "class AClass(ABaseClass):" 340 | for function or operator: declaration - "([ = [# (read only)]" 342 | "decorator": (optional) "@classmethod" or "@staticmethod" 343 | "description": (optional) general description of the element 344 | "hint" : (optional) formatting hint for the doc2definition() function: "property" for RNA properties, "class" for RNA structs 345 | then the list of function's arguments follows (if they exist) 346 | [argument name:] 347 | "name": argument's name (just to make the printing easier) 348 | "type": argument's type (may be a class name) 349 | "description": argument's description 350 | "ord": ordinal number 351 | ["@returns":] 352 | optional: what function/property returns: 353 | "description": description of the content 354 | "type": the name of returned type 355 | "ord": ordinal number (for functions) 356 | ["@note":] 357 | optional: note, added to description (below argument list) 358 | "description": description of the content 359 | "ord": ordinal number 360 | ["@seealso":] 361 | optional: reference, added to description (below argument list) 362 | "description": description of the content 363 | "ord": oridinal number 364 | 365 | ''' 366 | def type_name(name, include_namespace=False): 367 | ''' Helper function, that corrects some wrong type names 368 | Arguments: 369 | @name (string): "raw" name, received from RNA 370 | @include_namespace: True, when append the bpy.types. prefix 371 | returns the corrected type name (string) 372 | ''' 373 | if name in TYPE_ABERRATIONS: 374 | name = TYPE_ABERRATIONS[name] 375 | if include_namespace: 376 | name = "types." + name 377 | return name 378 | 379 | def get_argitem(arg, prev_ord, is_return=False): 380 | '''Helper function, that creates an argument definition subdictionary 381 | Arguments: 382 | @arg (rna_info.InfoPropertyRNA): descriptor of the argument 383 | @prev_ord (int): previous order index (to set the value for the "ord" key) 384 | 385 | Returns: an definistion subdictionary (keys: "name", "type", "description", "ord") 386 | ''' 387 | if arg.fixed_type: 388 | arg_type = arg.fixed_type.identifier 389 | else: 390 | arg_type = arg.type 391 | if is_return: 392 | description = arg.get_type_description(as_ret = True) #without default value! 393 | else: 394 | description = arg.get_type_description(as_arg = True) #without default value! 395 | 396 | if arg.collection_type == None: 397 | description = description.replace(arg_type, "", 1) #remove the first occurence of type name - it repeats the declaration! 398 | 399 | if description.startswith(","): #it may happen, when the arg_type was at the begining of the string: 400 | description = (description[1:]) #skip the leading colon 401 | if description.startswith(" "): 402 | description = (description[1:]) #skip first space 403 | 404 | #add some human comments (if it exists): 405 | if arg.description: 406 | description = arg.description + "\n" + _IDENT + description 407 | 408 | if is_return: 409 | return {"name":"returns", "description":description, "type":type_name(arg_type, arg.fixed_type != None), "ord":(prev_ord + 1)} 410 | else: 411 | return {"name":arg.identifier, "description":description, "type":type_name(arg_type), "ord":(prev_ord + 1)} 412 | 413 | def get_return(returns, prev_ord): 414 | '''Helper function, that creates the return definition subdictionary ("@returns") 415 | Arguments: 416 | @returns (list of rna_info.InfoPropertyRNA): descriptor of the return values 417 | @prev_ord (int): previous order index (to set the value for the "ord" key) 418 | 419 | Returns: an definistion subdictionary (keys: type", "description", "ord") 420 | ''' 421 | if len(returns) == 1: 422 | return get_argitem(returns[0],prev_ord,is_return = True) 423 | else: #many different values: 424 | description = "\n(" 425 | for ret in returns: 426 | item = get_argitem(ret, prev_ord, is_return = True) 427 | description = description + "\n{0}{1}({2}):{3}".format(_IDENT, ret.identifier, item.pop("type"), item.pop("description")) 428 | #give just the description, not the type! 429 | description = description + "\n)" 430 | return {"name":"returns", "description":description, "ord":(prev_ord + 1)} 431 | 432 | definition = {"@def":{"description":"", "ord":0}} #at the beginning: empty description of function definition 433 | 434 | if type(info) == rna_info.InfoStructRNA: 435 | #base class of this struct: 436 | base_id = getattr(info.base,"identifier",_BPY_STRUCT_FAKE) 437 | prototype = "class {0}(types.{1}):".format(info.identifier, base_id) 438 | definition["@def"].setdefault("prototype",prototype) 439 | definition["@def"]["description"] = info.description 440 | definition["@def"].setdefault("hint","class") 441 | 442 | elif type(info) == rna_info.InfoPropertyRNA: 443 | if info.collection_type: 444 | prop_type = info.collection_type.identifier 445 | elif info.fixed_type: 446 | prop_type = info.fixed_type.identifier 447 | else: 448 | prop_type = info.type 449 | prototype = "{0} = {1}".format(info.identifier, type_name(prop_type, info.fixed_type != None)) 450 | if info.is_readonly: 451 | prototype = prototype + " # (read only)" 452 | 453 | definition["@def"].setdefault("prototype",prototype) 454 | definition["@def"].setdefault("hint","property") 455 | 456 | if info.description: 457 | definition["@def"]["description"] = info.description 458 | 459 | definition.setdefault("@returns",{"name" : "returns", "description" : info.get_type_description(as_ret = True), "ord" : 1}) 460 | 461 | elif type(info) == rna_info.InfoFunctionRNA: 462 | args_str = ", ".join(prop.get_arg_default(force=False) for prop in info.args) 463 | prototype = "{0}({1})".format(info.identifier, args_str) 464 | definition["@def"].setdefault("prototype",prototype) 465 | if info.is_classmethod: definition["@def"].setdefault("decorator","@classmethod\n") 466 | definition["@def"]["description"] = info.description 467 | #append arguments: 468 | for arg in info.args: 469 | definition.setdefault(arg.identifier, get_argitem(arg,len(definition))) 470 | #append returns (operators have none): 471 | if info.return_values: 472 | definition.setdefault("@returns",get_return(info.return_values,len(definition))) 473 | 474 | elif type(info) == rna_info.InfoOperatorRNA: 475 | args_str = ", ".join(prop.get_arg_default(force=False) for prop in info.args) 476 | prototype = "{0}({1})".format(info.func_name, args_str) 477 | definition["@def"].setdefault("prototype",prototype) 478 | # definition["@def"].setdefault("decorator","@staticmethod\n") 479 | if info.description and info.description != "(undocumented operator)": 480 | definition["@def"]["description"] = info.description 481 | else: #just empty line 482 | definition["@def"]["description"] = "undocumented" 483 | #append arguments: 484 | for arg in info.args: 485 | definition.setdefault(arg.identifier, get_argitem(arg,len(definition))) 486 | else: 487 | raise TypeError("type was not InfoFunctionRNA, InfoStructRNA, InfoPropertyRNA or InfoOperatorRNA") 488 | 489 | return definition 490 | 491 | def doc2definition(doc,docstring_ident=_IDENT): 492 | '''Method converts given doctext into declaration and docstring comment 493 | Details: 494 | @doc (string or list) - the documentation text of the member (preferably in sphinx RST syntax) 495 | or ready dictionary of dictionaries, like the result of rst2list() (see above) 496 | @docstring_ident (string) - the amount of spaces before docstring markings 497 | @function - function, that should be used to get the list 498 | Returns: dictionary with following elements: 499 | "declaration": function declaration (may be omitted for attributes docstrings) 500 | "docstring": properly idented docstring (leading and trailing comment markings included) 501 | "returns": type, returned by property/function (to use in eventual return statement) 502 | ''' 503 | def pop(definition,key): 504 | '''Removes the given element form the dictionary 505 | Arguments: 506 | @definition: dictionary[key] 507 | @key: the key in the definition dictionary 508 | ''' 509 | if key in definition: 510 | return definition.pop(key) 511 | else: 512 | return None 513 | 514 | def format_arg(data): 515 | '''Returns line of text, describing an argument or return statement 516 | Arguments: 517 | data (dictionary): a "subdictionary" of , describing single item: 518 | ("ord", "name", ["description"],["type"]) 519 | ''' 520 | if "type" in data and "description" in data: 521 | return "@{name} ({type}): {description}".format(**data) 522 | elif "type" in data: 523 | return "@{name} ({type}): ".format(**data) 524 | elif "description" in data: 525 | return "@{name}: {description}".format(**data) 526 | else: 527 | return "@{name}: ".format(**data) 528 | 529 | def get(definition,key,subkey): 530 | ''' Returns the given value from the definition dictionary, or None 531 | when it does not exists 532 | Arguments: 533 | @definition: dictionary[key] of dictionaries[subkey] 534 | @key: the key in the definition dictionary 535 | @subkey: the key in the definition[key] subdictionary 536 | ''' 537 | if key in definition: 538 | if subkey in definition[key]: 539 | return definition[key][subkey] 540 | else: 541 | return None 542 | else: 543 | return None 544 | 545 | if doc is None: 546 | return {"docstring" : docstring_ident + "\n"} 547 | 548 | if type(doc) is str : 549 | definition = rst2list(doc) 550 | else: 551 | definition = doc #assume, that doc is the ready definition list! 552 | 553 | rtype = get(definition,"@def","type") 554 | if rtype is None: 555 | rtype = get(definition,"@returns","type") #for functions 556 | 557 | _returns = pop(definition, "@returns") 558 | 559 | _note = pop(definition,"@note") 560 | 561 | _seealso = pop(definition, "@seealso") 562 | 563 | declaration = get(definition, "@def","prototype") 564 | decorator = get(definition, "@def", "decorator") 565 | hint = get(definition, "@def", "hint") 566 | if declaration: 567 | if hint in ("property", "class"): 568 | pass #no prefix needed 569 | elif decorator: 570 | declaration = decorator + "def " + declaration +":" 571 | else: 572 | declaration = "def " + declaration +":" 573 | 574 | _def = pop(definition, "@def") #remove the definition from the list.... 575 | 576 | ident = docstring_ident + _IDENT #all next row will have additional ident, to match the first line 577 | lines = [] #lines of the docstring text 578 | 579 | al = lines.append #trick, to re-use the write_indented_lines to add the line 580 | 581 | if "description" in _def: 582 | write_indented_lines(ident,al,_def["description"],False) #fill the list 583 | if lines: 584 | lines[0] = lines[0][len(ident):] #skip the ident in the first and the last line: 585 | # (the docstring's prefix " '''" will be placed there) 586 | 587 | if definition.keys(): #Are named arguments there? 588 | write_indented_lines(ident,al,"Arguments:",False) 589 | 590 | for tuple in sorted(definition.items(),key = lambda item: item[1]["ord"]): #sort the lines in the original sequence 591 | #first item of the is the key, second - the value (dictionary describing a single element) 592 | write_indented_lines(ident,al,format_arg(tuple[1]),False) 593 | #end for 594 | al("\n") 595 | 596 | if _returns: 597 | write_indented_lines(ident,al,format_arg(_returns),False) 598 | 599 | if _note and "description" in _note: 600 | write_indented_lines(ident,al,"Note: " + _note["description"],False) 601 | 602 | if _seealso and "description" in _seealso: 603 | write_indented_lines(ident,al,"(seealso " + _seealso["description"]+")\n",False) 604 | 605 | if not lines: 606 | lines.append("\n") 607 | 608 | result = {"docstring" : docstring_ident + "'''" + "".join(lines)+ docstring_ident + "'''\n"} 609 | 610 | if declaration: 611 | result.setdefault("declaration",declaration) 612 | 613 | if rtype: 614 | result.setdefault("returns",rtype) 615 | 616 | return result 617 | 618 | def pyfunc2predef(ident, fw, identifier, py_func, is_class=True): 619 | ''' Creates declaration of a function or class method 620 | Details: 621 | @ident (string): the required prefix (spaces) 622 | @fw (function): the unified shortcut to print() or file.write() function 623 | @identifier (string): the name of the member 624 | @py_func (): the method, that is being described here 625 | @is_class (boolean): True, when it is a class member 626 | ''' 627 | try: 628 | arguments = inspect.getargspec(py_func) 629 | if len(arguments.args) == 0 and is_class: 630 | fw(ident+"@staticmethod\n") 631 | elif len(arguments.args)==0: #global function (is_class = false) 632 | pass 633 | elif arguments.args[0] == "cls" and is_class: 634 | fw(ident+"@classmethod\n") 635 | else: #global function 636 | pass 637 | 638 | definition = doc2definition(py_func.__doc__) #parse the eventual RST sphinx markup 639 | 640 | if "declaration" in definition: 641 | write_indented_lines(ident,fw, definition["declaration"],False) 642 | else: 643 | arg_str = inspect.formatargspec(*arguments) 644 | fmt = ident + "def %s%s:\n" 645 | fw(fmt % (identifier, arg_str)) 646 | 647 | if "docstring" in definition: 648 | write_indented_lines(ident,fw,definition["docstring"],False) 649 | 650 | if "returns" in definition: 651 | write_indented_lines(ident+_IDENT,fw,"return " + definition["returns"],False) 652 | else: 653 | write_indented_lines(ident+_IDENT,fw,"pass",False) 654 | 655 | fw(ident + "\n") 656 | except: 657 | msg = "#unable to describe the '%s' method due to internal error\n\n" % identifier 658 | fw(ident + msg) 659 | 660 | def py_descr2predef(ident, fw, descr, module_name, type_name, identifier): 661 | ''' Creates declaration of a function or class method 662 | Details: 663 | @ident (string): the required prefix (spaces) 664 | @fw (function): the unified shortcut to print() or file.write() function 665 | @descr(): an object, describing the member 666 | @module_name (string): the name of this module 667 | @type_name (string): the name of the containing class 668 | @identifier (string): the name of the member 669 | ''' 670 | 671 | if identifier.startswith("_"): 672 | return 673 | 674 | if type(descr) in (types.GetSetDescriptorType, types.MemberDescriptorType): #an attribute of the module or class 675 | definition = doc2definition(descr.__doc__,"") #parse the eventual RST sphinx markup 676 | if "returns" in definition: 677 | returns = definition["returns"] 678 | else: 679 | returns = "None" #we have to assign just something, to be properly parsed! 680 | 681 | fw(ident + identifier + " = " + returns + "\n") 682 | 683 | if "docstring" in definition: 684 | write_indented_lines(ident,fw,definition["docstring"],False) 685 | 686 | elif type(descr) in (MethodDescriptorType, ClassMethodDescriptorType): 687 | py_c_func2predef(ident,fw,module_name,type_name,identifier,descr,True) 688 | else: 689 | raise TypeError("type was not MemberDescriptiorType, GetSetDescriptorType, MethodDescriptorType or ClassMethodDescriptorType") 690 | fw("\n") 691 | 692 | 693 | def py_c_func2predef(ident, fw, module_name, type_name, identifier, py_func, is_class=True): 694 | ''' Creates declaration of a function or class method 695 | Details: 696 | @ident (string): the required prefix (spaces) 697 | @fw (function): the unified shortcut to print() or file.write() function 698 | @type_name (string): the name of the class 699 | @py_func (): the method, that is being described here 700 | @is_class (boolean): True, when it is a class member 701 | ''' 702 | definition = doc2definition(py_func.__doc__) #parse the eventual RST sphinx markup 703 | if type(py_func)== ClassMethodDescriptorType: 704 | fw(ident+"@classmethod\n") 705 | 706 | if "declaration" in definition: 707 | write_indented_lines(ident,fw, definition["declaration"],False) 708 | else: 709 | fw(ident + "def %s(*argv):\n" % identifier)#*argv, because we do not know about its arguments.... 710 | 711 | if "docstring" in definition: 712 | write_indented_lines(ident,fw,definition["docstring"],False) 713 | 714 | if "returns" in definition: 715 | write_indented_lines(ident+_IDENT,fw,"return " + definition["returns"],False) 716 | else: 717 | write_indented_lines(ident+_IDENT,fw,"pass",False) 718 | 719 | fw(ident + "\n") 720 | 721 | 722 | def pyprop2predef(ident, fw, identifier, py_prop): 723 | ''' Creates declaration of a property 724 | Details: 725 | @ident (string): the required prefix (spaces) 726 | @fw (function): the unified shortcut to print() or file.write() function 727 | @identifier (string): the name of the property 728 | @py_prop (): the property, that is being described here 729 | ''' 730 | definition = doc2definition(py_prop.__doc__,"") #parse the eventual RST sphinx markup 731 | if "returns" in definition: 732 | declaration = identifier + " = " + definition["returns"] 733 | else: 734 | declaration = identifier + " = None" #we have to assign just something, to be properly parsed! 735 | 736 | # readonly properties use "data" directive, variables use "attribute" directive 737 | if py_prop.fset is None: declaration = declaration + " # (readonly)" 738 | 739 | fw(ident + declaration + "\n") 740 | 741 | if "docstring" in definition: 742 | write_indented_lines(ident, fw, definition["docstring"], False) 743 | 744 | fw(ident + "\n") 745 | 746 | def pyclass2predef(fw, module_name, type_name, value): 747 | ''' Creates declaration of a class 748 | Details: 749 | @fw (function): the unified shortcut to print() or file.write() function 750 | @module_name (string): the name of the module, that contains this class 751 | @type_name (string): the name of the class 752 | @value (): the descriptor of this type 753 | ''' 754 | fw("class %s:\n" % type_name) 755 | definition = doc2definition(value.__doc__) #parse the eventual RST sphinx markup 756 | if "docstring" in definition: 757 | write_indented_lines("", fw, definition["docstring"], False) 758 | 759 | descr_items = [(key, descr) for key, descr in sorted(value.__dict__.items()) if not key.startswith("__")] 760 | 761 | for key, descr in descr_items: 762 | if type(descr) == ClassMethodDescriptorType: 763 | py_descr2predef(_IDENT, fw, descr, module_name, type_name, key) 764 | 765 | for key, descr in descr_items: 766 | if type(descr) == MethodDescriptorType: 767 | py_descr2predef(_IDENT, fw, descr, module_name, type_name, key) 768 | 769 | for key, descr in descr_items: 770 | if type(descr) in {types.FunctionType, types.MethodType}: 771 | pyfunc2predef(_IDENT, fw, key, descr) 772 | 773 | for key, descr in descr_items: 774 | if type(descr) == types.GetSetDescriptorType: 775 | py_descr2predef(_IDENT, fw, descr, module_name, type_name, key) 776 | 777 | for key, descr in descr_items: 778 | if type(descr) == PropertyType: 779 | pyprop2predef(_IDENT, fw, key, descr) 780 | 781 | fw("\n\n") 782 | 783 | def pymodule2predef(BASEPATH, module_name, module, title): 784 | attribute_set = set() 785 | filepath = os.path.join(BASEPATH, module_name + ".py") 786 | 787 | file = open(filepath, "w") 788 | fw = file.write 789 | #fw = print 790 | 791 | #The description of this module: 792 | if module.__doc__: 793 | title = title + "\n" + module.__doc__ 794 | definition = doc2definition(title,"") #skip the leading spaces at the first line... 795 | fw(definition["docstring"]) 796 | fw("\n\n") 797 | 798 | # write members of the module 799 | # only tested with PyStructs which are not exactly modules 800 | # List the properties, first: 801 | for key, descr in sorted(type(module).__dict__.items()): 802 | if key.startswith("__"): 803 | continue 804 | # naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect. 805 | if type(descr) == types.GetSetDescriptorType : # 'bpy_app_type' name is only used for examples and messages 806 | py_descr2predef("", fw, descr, module_name, "bpy_app_type", key) 807 | attribute_set.add(key) 808 | 809 | # Then list the attributes: 810 | for key, descr in sorted(type(module).__dict__.items()): 811 | if key.startswith("__"): 812 | continue 813 | # naughty, we also add getset's into PyStructs, this is not typical py but also not incorrect. 814 | if type(descr) == types.MemberDescriptorType: # 'bpy_app_type' name is only used for examples and messages 815 | py_descr2predef("", fw, descr, module_name, "", key) 816 | attribute_set.add(key) 817 | 818 | del key, descr 819 | 820 | #list classes: 821 | classes = [] 822 | 823 | for attribute in sorted(dir(module)): 824 | if not attribute.startswith("_"): 825 | 826 | if attribute in attribute_set: #skip the processed items: 827 | continue 828 | 829 | if attribute.startswith("n_"): # annoying exception, needed for bpy.app 830 | continue 831 | 832 | value = getattr(module, attribute) 833 | 834 | value_type = type(value) 835 | 836 | if value_type == types.FunctionType: 837 | pyfunc2predef("", fw, attribute, value, is_class=False) 838 | 839 | elif value_type in (types.BuiltinMethodType, types.BuiltinFunctionType): # both the same at the moment but to be future proof 840 | # note: can't get args from these, so dump the string as is 841 | # this means any module used like this must have fully formatted docstrings. 842 | py_c_func2predef("", fw, module_name, module, attribute, value, is_class=False) 843 | 844 | elif value_type == type: 845 | classes.append((attribute, value)) 846 | 847 | elif value_type in (bool, int, float, str, tuple): 848 | # constant, not much fun we can do here except to list it. 849 | # TODO, figure out some way to document these! 850 | fw("{0} = {1} #constant value \n\n".format(attribute,repr(value))) 851 | 852 | else: 853 | print("\tnot documenting %s.%s" % (module_name, attribute)) 854 | continue 855 | 856 | attribute_set.add(attribute) 857 | # TODO, more types... 858 | 859 | # write collected classes now 860 | for (type_name, value) in classes: 861 | pyclass2predef(fw, module_name, type_name, value) 862 | 863 | file.close() 864 | 865 | def rna_property2predef(ident, fw, descr): 866 | ''' Creates declaration of a property 867 | Details: 868 | @ident (string): the required prefix (spaces) 869 | @fw (function): the unified shortcut to print() or file.write() function 870 | @descr (rna_info.InfoPropertyRNA): descriptor of the property 871 | ''' 872 | definition = doc2definition(rna2list(descr),docstring_ident="") 873 | write_indented_lines(ident,fw, definition["declaration"],False) 874 | 875 | if "docstring" in definition: 876 | write_indented_lines(ident, fw, definition["docstring"], False) 877 | 878 | def rna_function2predef(ident, fw, descr): 879 | ''' Creates declaration of a function or operator 880 | Details: 881 | @ident (string): the required prefix (spaces) 882 | @fw (function): the unified shortcut to print() or file.write() function 883 | @descr (rna_info.InfoFunctionRNA or rna_info.InfoOperatorRNA): method's descriptor 884 | ''' 885 | definition = doc2definition(rna2list(descr)) 886 | write_indented_lines(ident,fw,definition["declaration"],False) #may contain two lines: decorator and declaration 887 | 888 | if "docstring" in definition: 889 | write_indented_lines(ident, fw, definition["docstring"], False) 890 | 891 | if "returns" in definition: 892 | write_indented_lines(ident+_IDENT,fw,"return " + definition["returns"],False) 893 | else: 894 | write_indented_lines(ident+_IDENT,fw,"pass",False) 895 | 896 | fw("\n") 897 | 898 | def rna_struct2predef(ident, fw, descr): 899 | ''' Creates declaration of a bpy structure 900 | Details: 901 | @ident (string): the required prefix (spaces) 902 | @fw (function): the unified shortcut to print() or file.write() function 903 | @descr (rna_info.InfoStructRNA): the descriptor of a Blender Python class 904 | ''' 905 | print("class %s:\n" % descr.identifier) 906 | definition = doc2definition(rna2list(descr)) 907 | write_indented_lines(ident,fw, definition["declaration"],False) 908 | 909 | if "docstring" in definition: 910 | write_indented_lines(ident, fw, definition["docstring"], False) 911 | 912 | #native properties 913 | ident = ident + _IDENT 914 | properties = descr.properties 915 | properties.sort(key= lambda prop: prop.identifier) 916 | for prop in properties: 917 | rna_property2predef(ident,fw,prop) 918 | 919 | #Python properties 920 | properties = descr.get_py_properties() 921 | for identifier, prop in properties: 922 | pyprop2predef(ident,fw,identifier,prop) 923 | 924 | #Blender native functions 925 | functions = descr.functions 926 | for function in functions: 927 | rna_function2predef(ident, fw, function) 928 | 929 | functions = descr.get_py_functions() 930 | for identifier, function in functions: 931 | pyfunc2predef(ident, fw, identifier, function, is_class = True) 932 | 933 | def ops_struct2predef(ident, fw, module, operators): 934 | ''' Creates "pseudostructure" for a given module of operators 935 | Details: 936 | @ident (string): the required prefix (spaces) 937 | @fw (function): the unified shortcut to print() or file.write() function 938 | @module (string): one of bpy.ops names ("actions", for example) 939 | @operators (list of rna_info.InfoOperatorRNA): operators, grouped in this module 940 | ''' 941 | fmt = ident + "class {0}:\n" 942 | fw(fmt.format(module)) #"action" -> "class action:\n" 943 | ident = ident+_IDENT 944 | fw(ident+"'''Spcecial class, created just to reflect content of bpy.ops.{0}'''\n\n".format(module)) 945 | 946 | operators.sort(key=lambda op: op.func_name) 947 | 948 | for operator in operators: 949 | rna_function2predef(ident, fw, operator) 950 | 951 | def bpy_base2predef(ident, fw): 952 | ''' Creates a structure for the Blender base class 953 | Details: 954 | @ident (string): the required prefix (spaces) 955 | @fw (function): the unified shortcut to print() or file.write() function\n 956 | ''' 957 | fmt = ident + "class %s:\n" 958 | fw(fmt % _BPY_STRUCT_FAKE) 959 | ident = ident + _IDENT 960 | fw(ident + "'''built-in base class for all classes in bpy.types.\n\n") 961 | fmt = ident + _IDENT + "Note that bpy.types.%s is not actually available from within blender, it only exists for the purpose of documentation.\n" + ident + "'''\n\n" 962 | fw(fmt % _BPY_STRUCT_FAKE) 963 | 964 | descr_items = [(key, descr) for key, descr in sorted(bpy.types.Struct.__bases__[0].__dict__.items()) if not key.startswith("__")] 965 | 966 | for key, descr in descr_items: 967 | if type(descr) == MethodDescriptorType: # GetSetDescriptorType, GetSetDescriptorType's are not documented yet 968 | py_descr2predef(ident, fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key) 969 | 970 | for key, descr in descr_items: 971 | if type(descr) == types.GetSetDescriptorType: 972 | py_descr2predef(ident, fw, descr, "bpy.types", _BPY_STRUCT_FAKE, key) 973 | fw("\n\n") 974 | 975 | def bpy2predef(BASEPATH, title): 976 | ''' Creates the bpy.predef file. It contains the bpy.dta, bpy.ops, bpy.types 977 | Arguments: 978 | BASEPATH (string): path for the output file 979 | title(string): descriptive title (the comment for the whole module) 980 | ''' 981 | def property2predef(ident, fw, module, name): 982 | ''' writes definition of a named property 983 | Details: 984 | @ident (string): the required prefix (spaces) 985 | @fw (function): the unified shortcut to print() or file.write() function 986 | @module (string): one of bpy.ops names ("actions", for example) 987 | @name (string): name of the property 988 | ''' 989 | value = getattr(module, name, None) 990 | if value: 991 | value_type = getattr(value, "rna_type", None) 992 | if value_type: 993 | fw("{0} = types.{1}\n".format(name, value_type.identifier)) 994 | else: 995 | pyclass2predef(fw, modulr, name, value) 996 | fw("\n\n") 997 | 998 | #read all data: 999 | structs, funcs, ops, props = rna_info.BuildRNAInfo() 1000 | #open the file: 1001 | filepath = os.path.join(BASEPATH, "bpy.py") 1002 | file = open(filepath, "w") 1003 | fw = file.write 1004 | #Start the file: 1005 | definition = doc2definition(title,"") #skip the leading spaces at the first line... 1006 | fw(definition["docstring"]) 1007 | fw("\n\n") 1008 | 1009 | #group operators by modules: (dictionary of list of the operators) 1010 | op_modules = {} 1011 | for op in ops.values(): 1012 | op_modules.setdefault(op.module_name, []).append(op) 1013 | 1014 | #Special declaration of non-existing structiure just fo the ops member: 1015 | fw("class ops:\n") 1016 | fw(_IDENT+"'''Spcecial class, created just to reflect content of bpy.ops'''\n\n") 1017 | for op_module_name, ops_mod in sorted(op_modules.items(),key = lambda m : m[0]): 1018 | if op_module_name == "import": 1019 | continue 1020 | ops_struct2predef(_IDENT, fw, op_module_name, ops_mod) 1021 | 1022 | #classes (Blender structures:) 1023 | fw("class types:\n") 1024 | fw(_IDENT+"'''A container for all Blender types'''\n" + _IDENT + "\n") 1025 | 1026 | #base structure 1027 | bpy_base2predef(_IDENT, fw) 1028 | 1029 | #sort the type names: 1030 | classes = list(structs.values()) 1031 | classes.sort(key=lambda cls: cls.identifier) 1032 | 1033 | for cls in classes: 1034 | # skip the operators! 1035 | if "_OT_" not in cls.identifier: 1036 | rna_struct2predef(_IDENT, fw, cls) 1037 | 1038 | #the data members: 1039 | property2predef("", fw, bpy, "context") 1040 | 1041 | property2predef("", fw, bpy, "data") 1042 | 1043 | file.close() 1044 | 1045 | def rna2predef(BASEPATH): 1046 | 1047 | try: 1048 | os.mkdir(BASEPATH) 1049 | except: 1050 | pass 1051 | 1052 | if "bpy" in INCLUDE_MODULES: 1053 | bpy2predef(BASEPATH,"Blender API main module") 1054 | # internal modules 1055 | 1056 | module = None 1057 | 1058 | #if "bpy.context" not in EXCLUDE_MODULES: 1059 | # one of a kind, context doc (uses ctypes to extract info!) 1060 | #pycontext2sphinx(BASEPATH) 1061 | 1062 | # python modules 1063 | if "bpy.utils" in INCLUDE_MODULES: 1064 | from bpy import utils as module 1065 | pymodule2predef(BASEPATH, "bpy.utils", module, "Utilities (bpy.utils)") 1066 | 1067 | if "bpy.path" in INCLUDE_MODULES: 1068 | from bpy import path as module 1069 | pymodule2predef(BASEPATH, "bpy.path", module, "Path Utilities (bpy.path)") 1070 | 1071 | # C modules 1072 | if "bpy.app" in INCLUDE_MODULES: 1073 | from bpy import app as module 1074 | pymodule2predef(BASEPATH, "bpy.app", module, "Application Data (bpy.app)") 1075 | 1076 | if "bpy.props" in INCLUDE_MODULES: 1077 | from bpy import props as module 1078 | pymodule2predef(BASEPATH, "bpy.props", module, "Property Definitions (bpy.props)") 1079 | 1080 | if "mathutils" in INCLUDE_MODULES: 1081 | import mathutils as module 1082 | pymodule2predef(BASEPATH, "mathutils", module, "Math Types & Utilities (mathutils)") 1083 | 1084 | if "mathutils.geometry" in INCLUDE_MODULES: 1085 | import mathutils.geometry as module 1086 | pymodule2predef(BASEPATH, "mathutils.geometry", module, "Geometry Utilities (mathutils.geometry)") 1087 | 1088 | if "blf" in INCLUDE_MODULES: 1089 | import blf as module 1090 | pymodule2predef(BASEPATH, "blf", module, "Font Drawing (blf)") 1091 | 1092 | if "bgl" in INCLUDE_MODULES: 1093 | import bgl as module 1094 | pymodule2predef(BASEPATH, "bgl", module, "Open GL functions (bgl)") 1095 | 1096 | if "aud" in INCLUDE_MODULES: 1097 | import aud as module 1098 | pymodule2predef(BASEPATH, "aud", module, "Audio System (aud)") 1099 | 1100 | if "bmesh" in INCLUDE_MODULES: 1101 | import bmesh as module 1102 | pymodule2predef(BASEPATH, "bmesh", module, "BMesh mesh manipulations (bmesh)") 1103 | 1104 | if "bmesh.types" in INCLUDE_MODULES: 1105 | import bmesh.types as module 1106 | pymodule2predef(BASEPATH, "bmesh.types", module, "BMesh mesh manipulations types (bmesh.types)") 1107 | 1108 | del module 1109 | 1110 | def main(): 1111 | import bpy 1112 | if 'bpy' not in dir(): 1113 | print("\nError, this script must run from inside blender2.5") 1114 | print(script_help_msg) 1115 | else: 1116 | import shutil 1117 | 1118 | #these two strange lines below are just to make the debugging easier (to let it run many times from within Blender) 1119 | import imp 1120 | imp.reload(rna_info) #to avoid repeated arguments in function definitions on second and the next runs - a bug in rna_info.py.... 1121 | 1122 | if len(bpy.data.filepath)==0 or __file__[:len(bpy.data.filepath)] != bpy.data.filepath: 1123 | script_dir = os.path.dirname(__file__) 1124 | else: 1125 | #program run from text window has wacky filename 1126 | buffer_name = __file__[len(bpy.data.filepath) + 1:] 1127 | buffer = bpy.data.texts[buffer_name] 1128 | script_dir = os.path.dirname(buffer.filepath) #directory where this pypredef_gen.py script lives 1129 | 1130 | path_in = os.path.join(script_dir, "pypredef") 1131 | # only for partial updates 1132 | path_in_tmp = path_in + "-tmp" 1133 | 1134 | if not os.path.exists(path_in): 1135 | os.mkdir(path_in) 1136 | 1137 | # only for full updates 1138 | if _BPY_FULL_REBUILD: 1139 | shutil.rmtree(path_in, True) 1140 | else: 1141 | # write here, then move 1142 | shutil.rmtree(path_in_tmp, True) 1143 | 1144 | rna2predef(path_in_tmp) 1145 | 1146 | if not _BPY_FULL_REBUILD: 1147 | import filecmp 1148 | 1149 | # now move changed files from 'path_in_tmp' --> 'path_in' 1150 | file_list_path_in = set(os.listdir(path_in)) 1151 | file_list_path_in_tmp = set(os.listdir(path_in_tmp)) 1152 | 1153 | # remove deprecated files that have been removed. 1154 | for f in sorted(file_list_path_in): 1155 | if f not in file_list_path_in_tmp and f != "__pycache__": 1156 | print("\tdeprecated: %s" % f) 1157 | os.remove(os.path.join(path_in, f)) 1158 | 1159 | # freshen with new files. 1160 | for f in sorted(file_list_path_in_tmp): 1161 | f_from = os.path.join(path_in_tmp, f) 1162 | f_to = os.path.join(path_in, f) 1163 | 1164 | do_copy = True 1165 | if f in file_list_path_in: 1166 | if filecmp.cmp(f_from, f_to): 1167 | do_copy = False 1168 | 1169 | if do_copy: 1170 | print("\tupdating: %s" % f) 1171 | shutil.copy(f_from, f_to) 1172 | '''else: 1173 | print("\tkeeping: %s" % f) # eh, not that useful''' 1174 | 1175 | 1176 | 1177 | main() #just run it! Unconditional call makes it easier to debug Blender script in Eclipse, 1178 | # (using pydev_debug.py). It's doubtful, that it will be imported as additional module. 1179 | 1180 | 1181 | if __name__ == '__main__': 1182 | sys.exit() #Close Blender, when you run it from the command line.... 1183 | -------------------------------------------------------------------------------- /refresh_python_api: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | blender -b -P python_api/pypredef_gen.py 4 | --------------------------------------------------------------------------------