rna_info.py 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  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. # ##### END GPL LICENSE BLOCK #####
  18. # <pep8 compliant>
  19. # classes for extracting info from blenders internal classes
  20. import bpy
  21. # use to strip python paths
  22. script_paths = bpy.utils.script_paths()
  23. _FAKE_STRUCT_SUBCLASS = True
  24. def _get_direct_attr(rna_type, attr):
  25. props = getattr(rna_type, attr)
  26. base = rna_type.base
  27. if not base:
  28. return [prop for prop in props]
  29. else:
  30. props_base = getattr(base, attr).values()
  31. return [prop for prop in props if prop not in props_base]
  32. def get_direct_properties(rna_type):
  33. return _get_direct_attr(rna_type, "properties")
  34. def get_direct_functions(rna_type):
  35. return _get_direct_attr(rna_type, "functions")
  36. def rna_id_ignore(rna_id):
  37. if rna_id == "rna_type":
  38. return True
  39. if "_OT_" in rna_id:
  40. return True
  41. if "_MT_" in rna_id:
  42. return True
  43. if "_PT_" in rna_id:
  44. return True
  45. if "_HT_" in rna_id:
  46. return True
  47. if "_KSI_" in rna_id:
  48. return True
  49. return False
  50. def range_str(val):
  51. if val < -10000000:
  52. return "-inf"
  53. elif val > 10000000:
  54. return "inf"
  55. elif type(val) == float:
  56. return '%g' % val
  57. else:
  58. return str(val)
  59. def float_as_string(f):
  60. val_str = "%g" % f
  61. if '.' not in val_str and '-' not in val_str: # value could be 1e-05
  62. val_str += '.0'
  63. return val_str
  64. def get_py_class_from_rna(rna_type):
  65. """ Gets the Python type for a class which isn't necessarily added to ``bpy.types``.
  66. """
  67. identifier = rna_type.identifier
  68. py_class = getattr(bpy.types, identifier, None)
  69. if py_class is not None:
  70. return py_class
  71. def subclasses_recurse(cls):
  72. for c in cls.__subclasses__():
  73. # is_registered
  74. if "bl_rna" in cls.__dict__:
  75. yield c
  76. yield from subclasses_recurse(c)
  77. while py_class is None:
  78. base = rna_type.base
  79. if base is None:
  80. raise Exception("can't find type")
  81. py_class_base = getattr(bpy.types, base.identifier, None)
  82. if py_class_base is not None:
  83. for cls in subclasses_recurse(py_class_base):
  84. if cls.bl_rna.identifier == identifier:
  85. return cls
  86. class InfoStructRNA:
  87. __slots__ = (
  88. "bl_rna",
  89. "identifier",
  90. "name",
  91. "description",
  92. "base",
  93. "nested",
  94. "full_path",
  95. "functions",
  96. "children",
  97. "references",
  98. "properties",
  99. )
  100. global_lookup = {}
  101. def __init__(self, rna_type):
  102. self.bl_rna = rna_type
  103. self.identifier = rna_type.identifier
  104. self.name = rna_type.name
  105. self.description = rna_type.description.strip()
  106. # set later
  107. self.base = None
  108. self.nested = None
  109. self.full_path = ""
  110. self.functions = []
  111. self.children = []
  112. self.references = []
  113. self.properties = []
  114. def build(self):
  115. rna_type = self.bl_rna
  116. parent_id = self.identifier
  117. self.properties[:] = [GetInfoPropertyRNA(rna_prop, parent_id)
  118. for rna_prop in get_direct_properties(rna_type) if rna_prop.identifier != "rna_type"]
  119. self.functions[:] = [GetInfoFunctionRNA(rna_prop, parent_id)
  120. for rna_prop in get_direct_functions(rna_type)]
  121. def get_bases(self):
  122. bases = []
  123. item = self
  124. while item:
  125. item = item.base
  126. if item:
  127. bases.append(item)
  128. return bases
  129. def get_nested_properties(self, ls=None):
  130. if not ls:
  131. ls = self.properties[:]
  132. if self.nested:
  133. self.nested.get_nested_properties(ls)
  134. return ls
  135. def _get_py_visible_attrs(self):
  136. attrs = []
  137. py_class = get_py_class_from_rna(self.bl_rna)
  138. for attr_str in dir(py_class):
  139. if attr_str.startswith("_"):
  140. continue
  141. attrs.append((attr_str, getattr(py_class, attr_str)))
  142. return attrs
  143. def get_py_properties(self):
  144. properties = []
  145. for identifier, attr in self._get_py_visible_attrs():
  146. if type(attr) is property:
  147. properties.append((identifier, attr))
  148. return properties
  149. def get_py_functions(self):
  150. import types
  151. functions = []
  152. for identifier, attr in self._get_py_visible_attrs():
  153. # methods may be python wrappers to C functions
  154. attr_func = getattr(attr, "__func__", attr)
  155. if type(attr_func) in {types.FunctionType, types.MethodType}:
  156. functions.append((identifier, attr))
  157. return functions
  158. def get_py_c_functions(self):
  159. import types
  160. functions = []
  161. for identifier, attr in self._get_py_visible_attrs():
  162. # methods may be python wrappers to C functions
  163. attr_func = getattr(attr, "__func__", attr)
  164. if type(attr_func) in {types.BuiltinMethodType, types.BuiltinFunctionType}:
  165. functions.append((identifier, attr))
  166. return functions
  167. def __str__(self):
  168. txt = ""
  169. txt += self.identifier
  170. if self.base:
  171. txt += "(%s)" % self.base.identifier
  172. txt += ": " + self.description + "\n"
  173. for prop in self.properties:
  174. txt += prop.__repr__() + "\n"
  175. for func in self.functions:
  176. txt += func.__repr__() + "\n"
  177. return txt
  178. class InfoPropertyRNA:
  179. __slots__ = (
  180. "bl_prop",
  181. "srna",
  182. "identifier",
  183. "name",
  184. "description",
  185. "default_str",
  186. "default",
  187. "enum_items",
  188. "min",
  189. "max",
  190. "array_length",
  191. "array_dimensions",
  192. "collection_type",
  193. "type",
  194. "fixed_type",
  195. "is_argument_optional",
  196. "is_enum_flag",
  197. "is_required",
  198. "is_readonly",
  199. "is_never_none",
  200. )
  201. global_lookup = {}
  202. def __init__(self, rna_prop):
  203. self.bl_prop = rna_prop
  204. self.identifier = rna_prop.identifier
  205. self.name = rna_prop.name
  206. self.description = rna_prop.description.strip()
  207. self.default_str = "<UNKNOWN>"
  208. def build(self):
  209. rna_prop = self.bl_prop
  210. self.enum_items = []
  211. self.min = getattr(rna_prop, "hard_min", -1)
  212. self.max = getattr(rna_prop, "hard_max", -1)
  213. self.array_length = getattr(rna_prop, "array_length", 0)
  214. self.array_dimensions = getattr(rna_prop, "array_dimensions", ())[:]
  215. self.collection_type = GetInfoStructRNA(rna_prop.srna)
  216. self.is_required = rna_prop.is_required
  217. self.is_readonly = rna_prop.is_readonly
  218. self.is_never_none = rna_prop.is_never_none
  219. self.is_argument_optional = rna_prop.is_argument_optional
  220. self.type = rna_prop.type.lower()
  221. fixed_type = getattr(rna_prop, "fixed_type", "")
  222. if fixed_type:
  223. self.fixed_type = GetInfoStructRNA(fixed_type) # valid for pointer/collections
  224. else:
  225. self.fixed_type = None
  226. if self.type == "enum":
  227. self.enum_items[:] = [(item.identifier, item.name, item.description) for item in rna_prop.enum_items]
  228. self.is_enum_flag = rna_prop.is_enum_flag
  229. else:
  230. self.is_enum_flag = False
  231. self.default_str = "" # fallback
  232. if self.array_length:
  233. self.default = tuple(getattr(rna_prop, "default_array", ()))
  234. if self.array_dimensions[1] != 0: # Multi-dimensional array, convert default flat one accordingly.
  235. self.default_str = tuple(float_as_string(v) if self.type == "float" else str(v) for v in self.default)
  236. for dim in self.array_dimensions[::-1]:
  237. if dim != 0:
  238. self.default = tuple(zip(*((iter(self.default),) * dim)))
  239. self.default_str = tuple("(%s)" % ", ".join(s for s in b) for b in zip(*((iter(self.default_str),) * dim)))
  240. self.default_str = self.default_str[0]
  241. elif self.type == "enum" and self.is_enum_flag:
  242. self.default = getattr(rna_prop, "default_flag", set())
  243. else:
  244. self.default = getattr(rna_prop, "default", None)
  245. if self.type == "pointer":
  246. # pointer has no default, just set as None
  247. self.default = None
  248. self.default_str = "None"
  249. elif self.type == "string":
  250. self.default_str = "\"%s\"" % self.default
  251. elif self.type == "enum":
  252. if self.is_enum_flag:
  253. # self.default_str = "%r" % self.default # repr or set()
  254. self.default_str = "{%s}" % repr(list(sorted(self.default)))[1:-1]
  255. else:
  256. self.default_str = "'%s'" % self.default
  257. elif self.array_length:
  258. if self.array_dimensions[1] == 0: # single dimension array, we already took care of multi-dimensions ones.
  259. # special case for floats
  260. if self.type == "float" and len(self.default) > 0:
  261. self.default_str = "(%s)" % ", ".join(float_as_string(f) for f in self.default)
  262. else:
  263. self.default_str = str(self.default)
  264. else:
  265. if self.type == "float":
  266. self.default_str = float_as_string(self.default)
  267. else:
  268. self.default_str = str(self.default)
  269. self.srna = GetInfoStructRNA(rna_prop.srna) # valid for pointer/collections
  270. def get_arg_default(self, force=True):
  271. default = self.default_str
  272. if default and (force or self.is_required is False):
  273. return "%s=%s" % (self.identifier, default)
  274. return self.identifier
  275. def get_type_description(self, as_ret=False, as_arg=False, class_fmt="%s", collection_id="Collection"):
  276. type_str = ""
  277. if self.fixed_type is None:
  278. type_str += self.type
  279. if self.array_length:
  280. if self.array_dimensions[1] != 0:
  281. type_str += " multi-dimensional array of %s items" % (" * ".join(str(d) for d in self.array_dimensions if d != 0))
  282. else:
  283. type_str += " array of %d items" % (self.array_length)
  284. if self.type in {"float", "int"}:
  285. type_str += " in [%s, %s]" % (range_str(self.min), range_str(self.max))
  286. elif self.type == "enum":
  287. if self.is_enum_flag:
  288. type_str += " set in {%s}" % ", ".join(("'%s'" % s[0]) for s in self.enum_items)
  289. else:
  290. type_str += " in [%s]" % ", ".join(("'%s'" % s[0]) for s in self.enum_items)
  291. if not (as_arg or as_ret):
  292. # write default property, ignore function args for this
  293. if self.type != "pointer":
  294. if self.default_str:
  295. type_str += ", default %s" % self.default_str
  296. else:
  297. if self.type == "collection":
  298. if self.collection_type:
  299. collection_str = (class_fmt % self.collection_type.identifier) + (" %s of " % collection_id)
  300. else:
  301. collection_str = "%s of " % collection_id
  302. else:
  303. collection_str = ""
  304. type_str += collection_str + (class_fmt % self.fixed_type.identifier)
  305. # setup qualifiers for this value.
  306. type_info = []
  307. if as_ret:
  308. pass
  309. elif as_arg:
  310. if not self.is_required:
  311. type_info.append("optional")
  312. if self.is_argument_optional:
  313. type_info.append("optional argument")
  314. else: # readonly is only useful for self's, not args
  315. if self.is_readonly:
  316. type_info.append("readonly")
  317. if self.is_never_none:
  318. type_info.append("never None")
  319. if type_info:
  320. type_str += (", (%s)" % ", ".join(type_info))
  321. return type_str
  322. def __str__(self):
  323. txt = ""
  324. txt += " * " + self.identifier + ": " + self.description
  325. return txt
  326. class InfoFunctionRNA:
  327. __slots__ = (
  328. "bl_func",
  329. "identifier",
  330. "description",
  331. "args",
  332. "return_values",
  333. "is_classmethod",
  334. )
  335. global_lookup = {}
  336. def __init__(self, rna_func):
  337. self.bl_func = rna_func
  338. self.identifier = rna_func.identifier
  339. # self.name = rna_func.name # functions have no name!
  340. self.description = rna_func.description.strip()
  341. self.is_classmethod = not rna_func.use_self
  342. self.args = []
  343. self.return_values = ()
  344. def build(self):
  345. rna_func = self.bl_func
  346. parent_id = rna_func
  347. self.return_values = []
  348. for rna_prop in rna_func.parameters.values():
  349. prop = GetInfoPropertyRNA(rna_prop, parent_id)
  350. if rna_prop.is_output:
  351. self.return_values.append(prop)
  352. else:
  353. self.args.append(prop)
  354. self.return_values = tuple(self.return_values)
  355. def __str__(self):
  356. txt = ''
  357. txt += ' * ' + self.identifier + '('
  358. for arg in self.args:
  359. txt += arg.identifier + ', '
  360. txt += '): ' + self.description
  361. return txt
  362. class InfoOperatorRNA:
  363. __slots__ = (
  364. "bl_op",
  365. "identifier",
  366. "name",
  367. "module_name",
  368. "func_name",
  369. "description",
  370. "args",
  371. )
  372. global_lookup = {}
  373. def __init__(self, rna_op):
  374. self.bl_op = rna_op
  375. self.identifier = rna_op.identifier
  376. mod, name = self.identifier.split("_OT_", 1)
  377. self.module_name = mod.lower()
  378. self.func_name = name
  379. # self.name = rna_func.name # functions have no name!
  380. self.description = rna_op.description.strip()
  381. self.args = []
  382. def build(self):
  383. rna_op = self.bl_op
  384. parent_id = self.identifier
  385. for rna_id, rna_prop in rna_op.properties.items():
  386. if rna_id == "rna_type":
  387. continue
  388. prop = GetInfoPropertyRNA(rna_prop, parent_id)
  389. self.args.append(prop)
  390. def get_location(self):
  391. try:
  392. op_class = getattr(bpy.types, self.identifier)
  393. except AttributeError:
  394. # defined in C.
  395. return None, None
  396. op_func = getattr(op_class, "execute", None)
  397. if op_func is None:
  398. op_func = getattr(op_class, "invoke", None)
  399. if op_func is None:
  400. op_func = getattr(op_class, "poll", None)
  401. if op_func:
  402. op_code = op_func.__code__
  403. source_path = op_code.co_filename
  404. # clear the prefix
  405. for p in script_paths:
  406. source_path = source_path.split(p)[-1]
  407. if source_path[0] in "/\\":
  408. source_path = source_path[1:]
  409. return source_path, op_code.co_firstlineno
  410. else:
  411. return None, None
  412. def _GetInfoRNA(bl_rna, cls, parent_id=""):
  413. if bl_rna is None:
  414. return None
  415. key = parent_id, bl_rna.identifier
  416. try:
  417. return cls.global_lookup[key]
  418. except KeyError:
  419. instance = cls.global_lookup[key] = cls(bl_rna)
  420. return instance
  421. def GetInfoStructRNA(bl_rna):
  422. return _GetInfoRNA(bl_rna, InfoStructRNA)
  423. def GetInfoPropertyRNA(bl_rna, parent_id):
  424. return _GetInfoRNA(bl_rna, InfoPropertyRNA, parent_id)
  425. def GetInfoFunctionRNA(bl_rna, parent_id):
  426. return _GetInfoRNA(bl_rna, InfoFunctionRNA, parent_id)
  427. def GetInfoOperatorRNA(bl_rna):
  428. return _GetInfoRNA(bl_rna, InfoOperatorRNA)
  429. def BuildRNAInfo():
  430. # needed on successive calls to prevent stale data access
  431. for cls in (InfoStructRNA, InfoFunctionRNA, InfoOperatorRNA, InfoPropertyRNA):
  432. cls.global_lookup.clear()
  433. del cls
  434. # Use for faster lookups
  435. # use rna_struct.identifier as the key for each dict
  436. rna_struct_dict = {} # store identifier:rna lookups
  437. rna_full_path_dict = {} # store the result of full_rna_struct_path(rna_struct)
  438. rna_children_dict = {} # store all rna_structs nested from here
  439. rna_references_dict = {} # store a list of rna path strings that reference this type
  440. # rna_functions_dict = {} # store all functions directly in this type (not inherited)
  441. def full_rna_struct_path(rna_struct):
  442. """
  443. Needed when referencing one struct from another
  444. """
  445. nested = rna_struct.nested
  446. if nested:
  447. return "%s.%s" % (full_rna_struct_path(nested), rna_struct.identifier)
  448. else:
  449. return rna_struct.identifier
  450. # def write_func(rna_func, ident):
  451. def base_id(rna_struct):
  452. try:
  453. return rna_struct.base.identifier
  454. except:
  455. return "" # invalid id
  456. #structs = [(base_id(rna_struct), rna_struct.identifier, rna_struct) for rna_struct in bpy.doc.structs.values()]
  457. '''
  458. structs = []
  459. for rna_struct in bpy.doc.structs.values():
  460. structs.append( (base_id(rna_struct), rna_struct.identifier, rna_struct) )
  461. '''
  462. structs = []
  463. for rna_type_name in dir(bpy.types):
  464. rna_type = getattr(bpy.types, rna_type_name)
  465. rna_struct = getattr(rna_type, "bl_rna", None)
  466. if rna_struct:
  467. # if not rna_type_name.startswith('__'):
  468. identifier = rna_struct.identifier
  469. if not rna_id_ignore(identifier):
  470. structs.append((base_id(rna_struct), identifier, rna_struct))
  471. # Simple lookup
  472. rna_struct_dict[identifier] = rna_struct
  473. # Store full rna path 'GameObjectSettings' -> 'Object.GameObjectSettings'
  474. rna_full_path_dict[identifier] = full_rna_struct_path(rna_struct)
  475. # Store a list of functions, remove inherited later
  476. # NOT USED YET
  477. ## rna_functions_dict[identifier] = get_direct_functions(rna_struct)
  478. # fill in these later
  479. rna_children_dict[identifier] = []
  480. rna_references_dict[identifier] = []
  481. else:
  482. print("Ignoring", rna_type_name)
  483. structs.sort() # not needed but speeds up sort below, setting items without an inheritance first
  484. # Arrange so classes are always defined in the correct order
  485. deps_ok = False
  486. while deps_ok is False:
  487. deps_ok = True
  488. rna_done = set()
  489. for i, (rna_base, identifier, rna_struct) in enumerate(structs):
  490. rna_done.add(identifier)
  491. if rna_base and rna_base not in rna_done:
  492. deps_ok = False
  493. data = structs.pop(i)
  494. ok = False
  495. while i < len(structs):
  496. if structs[i][1] == rna_base:
  497. structs.insert(i + 1, data) # insert after the item we depend on.
  498. ok = True
  499. break
  500. i += 1
  501. if not ok:
  502. print('Dependancy "%s" could not be found for "%s"' % (identifier, rna_base))
  503. break
  504. # Done ordering structs
  505. # precalculate vars to avoid a lot of looping
  506. for (rna_base, identifier, rna_struct) in structs:
  507. # rna_struct_path = full_rna_struct_path(rna_struct)
  508. rna_struct_path = rna_full_path_dict[identifier]
  509. for rna_prop in get_direct_properties(rna_struct):
  510. rna_prop_identifier = rna_prop.identifier
  511. if rna_prop_identifier == 'RNA' or rna_id_ignore(rna_prop_identifier):
  512. continue
  513. for rna_prop_ptr in (getattr(rna_prop, "fixed_type", None), getattr(rna_prop, "srna", None)):
  514. # Does this property point to me?
  515. if rna_prop_ptr and rna_prop_ptr.identifier in rna_references_dict:
  516. rna_references_dict[rna_prop_ptr.identifier].append(
  517. "%s.%s" % (rna_struct_path, rna_prop_identifier))
  518. for rna_func in get_direct_functions(rna_struct):
  519. for rna_prop_identifier, rna_prop in rna_func.parameters.items():
  520. if rna_prop_identifier == 'RNA' or rna_id_ignore(rna_prop_identifier):
  521. continue
  522. rna_prop_ptr = getattr(rna_prop, "fixed_type", None)
  523. # Does this property point to me?
  524. if rna_prop_ptr and rna_prop_ptr.identifier in rna_references_dict:
  525. rna_references_dict[rna_prop_ptr.identifier].append(
  526. "%s.%s" % (rna_struct_path, rna_func.identifier))
  527. # Store nested children
  528. nested = rna_struct.nested
  529. if nested:
  530. rna_children_dict[nested.identifier].append(rna_struct)
  531. # Sort the refs, just reads nicer
  532. for rna_refs in rna_references_dict.values():
  533. rna_refs.sort()
  534. info_structs = []
  535. for (rna_base, identifier, rna_struct) in structs:
  536. # if rna_struct.nested:
  537. # continue
  538. #write_struct(rna_struct, '')
  539. info_struct = GetInfoStructRNA(rna_struct)
  540. if rna_base:
  541. info_struct.base = GetInfoStructRNA(rna_struct_dict[rna_base])
  542. info_struct.nested = GetInfoStructRNA(rna_struct.nested)
  543. info_struct.children[:] = rna_children_dict[identifier]
  544. info_struct.references[:] = rna_references_dict[identifier]
  545. info_struct.full_path = rna_full_path_dict[identifier]
  546. info_structs.append(info_struct)
  547. for rna_info_prop in InfoPropertyRNA.global_lookup.values():
  548. rna_info_prop.build()
  549. for rna_info_prop in InfoFunctionRNA.global_lookup.values():
  550. rna_info_prop.build()
  551. done_keys = set()
  552. new_keys = set(InfoStructRNA.global_lookup.keys())
  553. while new_keys:
  554. for rna_key in new_keys:
  555. rna_info = InfoStructRNA.global_lookup[rna_key]
  556. rna_info.build()
  557. for prop in rna_info.properties:
  558. prop.build()
  559. for func in rna_info.functions:
  560. func.build()
  561. for prop in func.args:
  562. prop.build()
  563. for prop in func.return_values:
  564. prop.build()
  565. done_keys |= new_keys
  566. new_keys = set(InfoStructRNA.global_lookup.keys()) - done_keys
  567. # there are too many invalid defaults, unless we intend to fix, leave this off
  568. if 0:
  569. for rna_info in InfoStructRNA.global_lookup.values():
  570. for prop in rna_info.properties:
  571. # ERROR CHECK
  572. default = prop.default
  573. if type(default) in {float, int}:
  574. if default < prop.min or default > prop.max:
  575. print("\t %s.%s, %s not in [%s - %s]" %
  576. (rna_info.identifier, prop.identifier, default, prop.min, prop.max))
  577. # now for operators
  578. op_mods = dir(bpy.ops)
  579. for op_mod_name in sorted(op_mods):
  580. if op_mod_name.startswith('__'):
  581. continue
  582. op_mod = getattr(bpy.ops, op_mod_name)
  583. operators = dir(op_mod)
  584. for op in sorted(operators):
  585. try:
  586. rna_prop = getattr(op_mod, op).get_rna_type()
  587. except AttributeError:
  588. rna_prop = None
  589. except TypeError:
  590. rna_prop = None
  591. if rna_prop:
  592. GetInfoOperatorRNA(rna_prop)
  593. for rna_info in InfoOperatorRNA.global_lookup.values():
  594. rna_info.build()
  595. for rna_prop in rna_info.args:
  596. rna_prop.build()
  597. # for rna_info in InfoStructRNA.global_lookup.values():
  598. # print(rna_info)
  599. return (
  600. InfoStructRNA.global_lookup,
  601. InfoFunctionRNA.global_lookup,
  602. InfoOperatorRNA.global_lookup,
  603. InfoPropertyRNA.global_lookup,
  604. )
  605. def main():
  606. struct = BuildRNAInfo()[0]
  607. data = []
  608. for _struct_id, v in sorted(struct.items()):
  609. struct_id_str = v.identifier # "".join(sid for sid in struct_id if struct_id)
  610. for base in v.get_bases():
  611. struct_id_str = base.identifier + "|" + struct_id_str
  612. props = [(prop.identifier, prop) for prop in v.properties]
  613. for _prop_id, prop in sorted(props):
  614. # if prop.type == "boolean":
  615. # continue
  616. prop_type = prop.type
  617. if prop.array_length > 0:
  618. prop_type += "[%d]" % prop.array_length
  619. data.append(
  620. "%s.%s -> %s: %s%s %s" %
  621. (struct_id_str, prop.identifier, prop.identifier, prop_type,
  622. ", (read-only)" if prop.is_readonly else "", prop.description))
  623. data.sort()
  624. if bpy.app.background:
  625. import sys
  626. sys.stderr.write("\n".join(data))
  627. sys.stderr.write("\n\nEOF\n")
  628. else:
  629. text = bpy.data.texts.new(name="api.py")
  630. text.from_string(data)
  631. if __name__ == "__main__":
  632. main()