PageRenderTime 150ms CodeModel.GetById 22ms RepoModel.GetById 1ms app.codeStats 0ms

/documentation_src/library/generate_pi.py

https://github.com/kensington/kdevelop-python
Python | 1067 lines | 1056 code | 2 blank | 9 comment | 10 complexity | 11dbcb04f16cf797ee8ff461266ea9df MD5 | raw file
  1. """ generate_pi.py -- Generate Python interface by inspecting a module
  2. at runtime
  3. Copyright (c) 2001-2011, Archaeopteryx Software, Inc. All rights reserved.
  4. Written by John P. Ehresman and Stephan R.A. Deibel
  5. Permission is hereby granted, free of charge, to any person obtaining
  6. a copy of this software and associated documentation files (the
  7. "Software"), to deal in the Software without restriction, including
  8. without limitation the rights to use, copy, modify, merge, publish,
  9. distribute, sublicense, and/or sell copies of the Software, and to
  10. permit persons to whom the Software is furnished to do so, subject to
  11. the following conditions:
  12. The above copyright notice and this permission notice shall be
  13. included in all copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  15. EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  16. MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  17. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  18. CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  19. TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  20. SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. Simple utility to generate a python interface file from inspecting a module
  22. at run time. First argument is the name of the module. Subsequent arguments
  23. are name:expression pairs -- a class with given name will be created in the
  24. interface file with methods & attributes matching the methods & attributes
  25. of the object that results from the expression. The expression will be
  26. evaluated within the context of the module. The interface will be written
  27. to stdout.
  28. This contains some code specific to Python standard library code because it
  29. parses the docstring standards used there to determine information about
  30. return values. However, it works also with code that does not contain those
  31. type hints in docstrings (but return value type cannot be determined).
  32. """
  33. # IMPORTANT: This code has to run under all Python versions!
  34. import sys
  35. import os
  36. import string
  37. import stat
  38. try:
  39. import inspect
  40. except:
  41. inspect = None
  42. kIronPython = (sys.version_info >= (1, 6) and sys.version.find('IronPython') != -1)
  43. try:
  44. ascii_letters = string.ascii_letters
  45. except:
  46. ascii_letters = string.letters
  47. version = ((sys.hexversion & (0xff << 24)) >> 24,
  48. (sys.hexversion & 0x00ff0000) >> 16)
  49. def string_split(s, sep=' '):
  50. return s.split(sep)
  51. def string_join(s, sep):
  52. return sep.join(s)
  53. def string_find(s, t):
  54. return s.find(t)
  55. def string_strip(s):
  56. return s.strip()
  57. def string_replace(s, f, t, count=-1):
  58. return s.replace(f, t, count)
  59. def string_lower(s):
  60. return s.lower()
  61. def string_rfind(s, x):
  62. return s.rfind(x)
  63. def has_key(o, key):
  64. if version >= (3, 0):
  65. return key in o
  66. else:
  67. return o.has_key(key)
  68. if version >= (3, 0):
  69. def callable(o):
  70. return hasattr(o, '__call__')
  71. if version[0] == 1:
  72. printable_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'
  73. else:
  74. printable_chars = string.printable
  75. kOneLevelIndent = ' '
  76. kNoValue = []
  77. kStringTypes = [type('')]
  78. import types
  79. try:
  80. kStringTypes = types.StringTypes
  81. except:
  82. pass
  83. kLiteralTypes = [type(1), type(1.0), type(None)]
  84. try:
  85. kLiteralTypes.append(types.EllipsisType)
  86. kLiteralTypes.append(types.BooleanType)
  87. except:
  88. pass
  89. kStructureTypes = [type([]), type(()), type({})]
  90. kFileTypes = [type(sys.stdout)]
  91. if version >= (3, 0):
  92. kListType = type([])
  93. kTupleType = type(())
  94. kDictType = type({})
  95. else:
  96. kListType = types.ListType
  97. kTupleType = types.TupleType
  98. kDictType = types.DictType
  99. # Property support contributed by Nigel Rowe, Aug 10, 2007
  100. kPropertyTypes = []
  101. try:
  102. kPropertyTypes.append(type(property()))
  103. except:
  104. pass
  105. import types
  106. try:
  107. # types.GetSetDescriptorType only exists in python versions >= 2.5
  108. # and would otherwise need to be extracted from an extension module
  109. kPropertyTypes.append(types.GetSetDescriptorType)
  110. except:
  111. pass
  112. if kIronPython:
  113. import System
  114. kPropertyTypes.append(type(System.Version.Major))
  115. del System
  116. # Types of type, old-style class -- use C api names to be a bit clearer
  117. PyType_Type = type(type(''))
  118. class _OldStyleClass:
  119. pass
  120. PyClass_Type = type(_OldStyleClass)
  121. del _OldStyleClass
  122. kClassLikeTypes = [PyType_Type, PyClass_Type]
  123. def WriteDocString(obj, file, indent):
  124. """ Writes doc string for object if there is one. """
  125. quote = '"""'
  126. doc = getattr(obj, '__doc__', None)
  127. if doc == None:
  128. return
  129. doc = doc.replace('\r\n', '\n')
  130. if kIronPython or sys.version_info >= (3, 0):
  131. is_unicode = 0
  132. else:
  133. try:
  134. is_unicode = isinstance(doc, unicode)
  135. except:
  136. is_unicode = 0
  137. doc_parts = string_split(doc, '\n')
  138. for i in range(0, len(doc_parts)):
  139. line_repr = repr(doc_parts[i])
  140. if string_lower(line_repr[:1]) == 'u':
  141. line_repr = line_repr[1:]
  142. line_repr = line_repr[1:-1]
  143. line_parts = string_split(line_repr, quote)
  144. line_repr = string_join(line_parts, '\\' + quote)
  145. if i != 0:
  146. line_repr = indent + line_repr
  147. doc_parts[i] = line_repr
  148. doc = string_join(doc_parts, '\n')
  149. if is_unicode:
  150. file.write(indent + 'u%s %s %s\n' % (quote, doc, quote))
  151. else:
  152. file.write(indent + '%s %s %s\n' % (quote, doc, quote))
  153. def NextNonBlank(doc, i):
  154. for j in range(i, len(doc)):
  155. if doc[j] not in ' \t\r\n':
  156. return j
  157. return -1
  158. def FindFirstLine(doc):
  159. paren_count = 0
  160. bracket_count = 0
  161. brace_count = 0
  162. first_line = ''
  163. seen_chars = 0
  164. i = 0
  165. while i < len(doc):
  166. c = doc[i]
  167. if c == '(':
  168. paren_count = paren_count + 1
  169. elif c == '[':
  170. bracket_count = bracket_count + 1
  171. next_pos = NextNonBlank(doc, i+1)
  172. if doc[next_pos] == ',':
  173. first_line = first_line + ', ['
  174. i = next_pos + 1
  175. continue
  176. elif c == '{':
  177. brace_count = brace_count + 1
  178. elif c == ')':
  179. paren_count = paren_count - 1
  180. elif c == ']':
  181. bracket_count = bracket_count - 1
  182. next_pos = NextNonBlank(doc, i+1)
  183. if doc[next_pos] == '[':
  184. first_line = first_line + '], ['
  185. i = next_pos + 1
  186. bracket_count = bracket_count + 1
  187. continue
  188. elif c == '}':
  189. brace_count = brace_count - 1
  190. elif c in (' \t\r\n') and not seen_chars:
  191. i = i + 1
  192. continue
  193. elif c == '\n':
  194. if paren_count + bracket_count + brace_count == 0:
  195. return string_join(string_split(first_line), ' ')
  196. else:
  197. i = i + 1
  198. continue
  199. seen_chars = 1
  200. first_line = first_line + c
  201. i = i + 1
  202. return string_join(string_split(first_line), ' ')
  203. def ValidArgName(n):
  204. if len(n) == 0:
  205. return 0
  206. if n[0] not in '_' + ascii_letters:
  207. return 0
  208. for c in n[1:]:
  209. if c not in ascii_letters + string.digits + '_':
  210. return 0
  211. return 1
  212. def GetCallableSignatureIPy(val, obj, name):
  213. import_line = None
  214. return_line = 'pass'
  215. doc = getattr(val, '__doc__', None)
  216. if doc is None:
  217. return '', None, 'pass'
  218. import clr
  219. try:
  220. clr_type = clr.GetClrType(obj)
  221. except TypeError:
  222. # XXXXX happens when we get namespace tracker objects
  223. # Annoying ????
  224. sys.stderr.write('@@@@@ Class %s is not a type. (Method = %s)\n' % (obj, name))
  225. a, b = GetCallableSignature(val)
  226. return a, None, b
  227. methods = [m for m in clr_type.GetMethods() if m.Name == name]
  228. # Very occasionally (e.g. Microsoft.CSharp.CSharpCodeProvider.CreateProvider)
  229. # We fail to find the method. Also happens for some IronPython methods
  230. # Like ReferenceEquals and ToObject (inherited methods?)
  231. if not methods:
  232. sys.stderr.write('Unlikely as it may sound, class %s has no method %s\n' % (obj, name))
  233. a, b = GetCallableSignature(val)
  234. return a, None, b
  235. # XXXX if len(methods) > 1 we have multiple overloads
  236. # what to do? Just use the first.
  237. method = methods[0]
  238. return_type = method.ReturnType
  239. if return_type is not None:
  240. ns = return_type.Namespace
  241. import_line = 'import %s' % ns
  242. return_line = 'return %s.%s()' % (ns, return_type.Name)
  243. parameter_info = method.GetParameters()
  244. params = [p.Name for p in parameter_info]
  245. if not method.IsStatic:
  246. params = ['self'] + params
  247. return string_join(params, ', '), import_line, return_line
  248. def GetCallableSignature(obj):
  249. doc = getattr(obj, '__doc__', None)
  250. if doc is None:
  251. return '', 'pass'
  252. if kIronPython:
  253. return _IronPythonGetCallableSignature(doc)
  254. else:
  255. return _GetCallableSignature(doc)
  256. def _GetCallableSignature(doc):
  257. try:
  258. return __GetCallableSignature(doc)
  259. except:
  260. import traceback
  261. sys.stderr.write("Error parsing call signature from docstring:\n")
  262. sys.stderr.write(doc)
  263. etype, evalue, etb = sys.exc_info()
  264. sys.stderr.write(string_join(traceback.format_exception(etype, evalue, etb), '\n'))
  265. return '', 'pass'
  266. import re
  267. ret_val_re = re.compile(r'^(?: )?([A-Za-z][A-Za-z0-9_\-]*)(?: |\[.*\] ).*\(.*\)') # Yuck!!!
  268. def _IronPythonGetCallableSignature(doc):
  269. a, b = _GetCallableSignature(doc)
  270. if b != 'pass':
  271. return a, b
  272. mat = ret_val_re.match(doc)
  273. if mat is None:
  274. return a, 'pass'
  275. ret_val = 'return ' + mat.groups()[0] + '()'
  276. sys.stderr.write('#### Generating return value of %s\n' % repr(ret_val))
  277. return a, ret_val
  278. def _ParseArgs(args):
  279. """ Parse args string w/o opening and closing () into list of argument
  280. names. """
  281. args = string_strip(args)
  282. if args == '':
  283. return []
  284. # Parse each argument
  285. arglist = string_split(args, ',')
  286. parsed_args = []
  287. arg_count = 0
  288. seen_defaults = 0
  289. for i in range(0, len(arglist)):
  290. arg = string_strip(arglist[i])
  291. if string_find(arg, '=') > 0:
  292. seen_defaults = 1
  293. # Remove and count []'s indicating optional args
  294. fixed_arg = ''
  295. for c in arg:
  296. if c == '[':
  297. seen_defaults = 1
  298. elif c == ']':
  299. pass
  300. else:
  301. fixed_arg = fixed_arg + c
  302. arg = string_strip(fixed_arg)
  303. arg = string_replace(arg, '-', '_')
  304. # Remove surrounding quote seen in some cases for no apparent reason
  305. if len(arg) > 2 and arg[0] in ('"', "'") and arg[-1] == arg[0]:
  306. arg = arg[1:-1]
  307. # Sometimes there's an extra comma; treat as anonymous arg
  308. if len(arg) == 0:
  309. arg = 'arg'
  310. # An optional argument of some type with default value or * or **
  311. if seen_defaults:
  312. # Rest of args
  313. if arg == '...':
  314. arg = '*args'
  315. # Verbal description: Create appropriate generic arg
  316. elif string_find(arg, ' ') >= 0:
  317. if string_find(arg, 'optional') == 0 and i == len(arglist) - 1:
  318. if seen_defaults:
  319. arg = '**argv'
  320. else:
  321. arg = '*argv'
  322. else:
  323. arg = 'arg%i=None' % arg_count
  324. seen_defaults = 1
  325. arg_count = arg_count + 1
  326. # Actual arg name -- add default if appropriate
  327. elif string_find(arg, '=') == -1 and arg[0] != '*':
  328. arg = arg + '=None'
  329. seen_defaults = 1
  330. elif arg == '...':
  331. seen_defaults = 1
  332. arg = '*args'
  333. # Use generic arg name if specified but not parseable
  334. elif len(arg) > 0 and not ValidArgName(arg):
  335. arg = 'arg%i' % arg_count
  336. arg_count = arg_count + 1
  337. if len(arg) > 0:
  338. parsed_args.append(arg)
  339. return parsed_args
  340. def __GetCallableSignature(doc):
  341. doc = string_replace(doc, '\r\n', '\n')
  342. doc = string_replace(doc, '\r', '\n')
  343. # Find the argument and return value spec in the docstring
  344. first_line = FindFirstLine(doc)
  345. #sys.stdout.write("FIRSTLINE %s" % str(first_line))
  346. args = None
  347. # Sometimes in form "spec -- comment" but also sometimes use --> or <==> instead of ->
  348. first_line = string_replace(first_line, '-->', '->')
  349. first_line = string_replace(first_line, '<==>', '->')
  350. if string_find(first_line, '--') >= 0:
  351. if string_find(first_line, '->') > 0:
  352. first_line = first_line[:string_find(first_line, '--')]
  353. else:
  354. first_line = string_replace(first_line, '--', '->', 1)
  355. if string_find(first_line, '->') >= 0:
  356. parts = string_split(first_line, '->')
  357. if len(parts) == 2:
  358. args, ret = parts
  359. elif string_find(first_line, '=') > 0:
  360. _parts = string_split(first_line, '=')
  361. parts = []
  362. for part in _parts:
  363. parts.append(string_strip(part))
  364. if len(parts) > 0 and string_find(parts[0], ' ') == -1:
  365. ret = parts[0]
  366. args = string_join(parts[1:], '=')
  367. lparen = string_find(args, '(')
  368. rparen = string_find(args, ')')
  369. if len(args) > 2 and lparen >= 0 and rparen > lparen:
  370. args = args[lparen+1:rparen]
  371. elif string_find(first_line, '(') >= 0:
  372. args = first_line
  373. ret = ''
  374. if args is None:
  375. lines = string_split(doc, '\n')
  376. if len(lines) == 1:
  377. return '', 'pass'
  378. else:
  379. return _GetCallableSignature(string_join(lines[1:], '\n'))
  380. # Extract arg spec from parenthesis
  381. lparen = string_find(args, '(')
  382. rparen = -1
  383. pos = lparen + 1
  384. nesting_count = 0
  385. while pos < len(args) and rparen == -1:
  386. if args[pos] == ')' and nesting_count == 0:
  387. rparen = pos
  388. elif args[pos] in '({[':
  389. nesting_count += 1
  390. elif args[pos] in ']})':
  391. nesting_count -= 1
  392. pos += 1
  393. if lparen >= 0 and rparen > lparen:
  394. args = args[lparen+1:rparen]
  395. parsed_args = _ParseArgs(args)
  396. # Build return specification
  397. retval = BuildReturnSpec(ret)
  398. if retval == '':
  399. retval = 'pass'
  400. else:
  401. retval = 'return ' + retval
  402. return string_join(parsed_args, ', '), retval
  403. def BuildReturnSpec(ret):
  404. ret = string_strip(ret)
  405. if len(ret) > 2 and ((ret[0] == '(' and ret[-1] == ')') or
  406. (ret[0] == '[' and ret[-1] == ']') or
  407. (ret[0] == '{' and ret[-1] == '}')):
  408. if string_find(ret, '...') >= 0:
  409. retval = ret[0] + ret[-1]
  410. else:
  411. ret_items = string_split(ret[1:-1], ',')
  412. fixed_items = []
  413. for item in ret_items:
  414. item = string_replace(string_strip(item), ' ', '_')
  415. item = string_replace(item, '-', '_')
  416. fixed_items.append(BuildReturnSpec(item))
  417. ret = ret[0] + string_join(fixed_items, ', ') + ret[-1]
  418. retval = ret
  419. elif string_find(ret, 'tuple') >= 0:
  420. retval = '()'
  421. elif string_find(ret, 'list') >= 0:
  422. retval = '[]'
  423. elif string_find(ret, 'dict') >= 0:
  424. retval = '{}'
  425. elif string_find(ret, 'str') >= 0:
  426. retval = '""'
  427. elif string_find(ret, 'file') >= 0:
  428. if version[0] == 1 or (version[0] == 2 and version[1] < 2):
  429. retval = '__FileObject()'
  430. else:
  431. retval = 'file(__file__)'
  432. elif string_find(ret, 'socket') >= 0:
  433. retval = 'SocketType()'
  434. elif string_find(ret, 'int') >= 0:
  435. retval = '1'
  436. elif string_find(ret, 'float') >= 0:
  437. retval = '1.0'
  438. elif len(ret) > 0:
  439. retval = 'None'
  440. else:
  441. retval = ''
  442. return retval
  443. kOmitTopLevel = ('__doc__', '__class__', '__new__', '__file__', '__name__', '__module__',
  444. '__builtins__')
  445. def ValidName(scope, name):
  446. if len(name) < 5:
  447. return 1
  448. if len(scope) == 1 and name in kOmitTopLevel:
  449. return 0
  450. if name[:2] == '__' and name[-2:] == '__':
  451. name = name[2:-2]
  452. if len(scope) > 1:
  453. return name == 'init'
  454. else:
  455. return 1
  456. else:
  457. return 1
  458. def GetValue(obj, slot, default):
  459. if type(obj) == type({}):
  460. return obj.get(slot, default)
  461. else:
  462. return getattr(obj, slot, default)
  463. def HasValue(obj, slot):
  464. if type(obj) == type({}):
  465. return has_key(obj, slot)
  466. else:
  467. return hasattr(obj, slot)
  468. def ValueItems(obj):
  469. if type(obj) == type({}):
  470. return obj.keys()
  471. elif type(obj) in kClassLikeTypes or type(obj) == types.ModuleType:
  472. return dir(obj)
  473. else:
  474. return ()
  475. def IsClassLike(val):
  476. for base in kClassLikeTypes:
  477. if isinstance(val, base):
  478. return 1
  479. return 0
  480. def IsFunctionOrMethod(val):
  481. return not IsClassLike(val) and callable(val)
  482. def SafeDir(o):
  483. try:
  484. return dir(o)
  485. except:
  486. return []
  487. def GenForObject(scope, overrides, overrides_file, obj, file, seen_vals, indent = '', use_inspect=0):
  488. # Use __all__ attrib if obj is a module
  489. name_list = None
  490. if isinstance(obj, type(sys)):
  491. name_list = getattr(obj, '__all__', None)
  492. elif type(obj) == type({}):
  493. name_list = obj.keys()
  494. if kIronPython:
  495. sys.stderr.write('**** generating %s\n' % repr(obj))
  496. if name_list == None:
  497. name_list = SafeDir(obj)
  498. last_val = kNoValue
  499. num_written = 0
  500. for name in name_list:
  501. if type(obj) == type({}):
  502. val = obj[name]
  503. else:
  504. # XXX Probably use kIronPython branch for CPython as well
  505. if kIronPython:
  506. val = obj.__dict__.get(name, None)
  507. if val is None:
  508. val = getattr(obj, name, None)
  509. else:
  510. val = getattr(obj, name, None)
  511. if kIronPython and name == 'None':
  512. name = 'None_'
  513. # skip nested namespaces
  514. if kIronPython:
  515. import System
  516. if isinstance(val, type(System)):
  517. continue
  518. if ValidName(scope, name) and (not hasattr(val, '__objclass__') or val.__objclass__ == obj):
  519. # Value is a class object
  520. if IsClassLike(val):
  521. # Skip overridden values if the override is not also a class object
  522. if HasValue(overrides, name):
  523. oval = GetValue(overrides, name, kNoValue)
  524. if oval is not kNoValue and type(oval) not in kClassLikeTypes:
  525. continue
  526. try:
  527. val_name = val.__name__
  528. except:
  529. val_name = None
  530. if val_name != name and val_name in name_list:
  531. if last_val is not kNoValue and not callable(last_val):
  532. file.write('\n')
  533. file.write(indent + '%s = %s\n' % (name, val_name))
  534. elif not has_key(seen_vals, val):
  535. try:
  536. seen_vals[val] = 1
  537. except TypeError:
  538. sys.stderr.write("Failed to register %s (may cause duplicates)\n" % str(val))
  539. if last_val is not kNoValue and not callable(last_val):
  540. file.write('\n')
  541. try:
  542. GenPClassForType(scope + [name], GetValue(overrides, name, {}), overrides_file,
  543. name, val, file, seen_vals, indent, use_inspect)
  544. except:
  545. pass # XXX May want to write exception to stderr
  546. num_written = num_written + 1
  547. # Try to use inspect module if requested, to place source directly (used
  548. # to write overrides)
  549. elif use_inspect and inspect is not None and IsFunctionOrMethod(val):
  550. try:
  551. src = inspect.getsource(val)
  552. except:
  553. #sys.stderr.write("NO SOURCE FOR NAME=%s TYPE=%s VAL=%s\n" % (name, str(type(val)), str(val)))
  554. pass
  555. else:
  556. if src:
  557. #sys.stderr.write("FOUND SOURCE FOR NAME=%s TYPE=%s VAL=%s\n" % (name, str(type(val)), str(val)))
  558. file.write(src + '\n')
  559. num_written = num_written + 1
  560. last_val = val
  561. continue
  562. #else:
  563. #sys.stderr.write("EMPTY SOURCE FOR NAME=%s TYPE=%s VAL=%s\n" % (name, str(type(val)), str(val)))
  564. # Skip functions, methods, or constants modified in overrides
  565. elif HasValue(overrides, name):
  566. continue
  567. # Value is a data-descriptor
  568. # Contributed by Nigel Rowe, Aug 10, 2007
  569. elif type(val) in kPropertyTypes:
  570. indent_to_paren = indent + ' ' * len(name) + ' ' * 12
  571. file.write(indent + '%s = property(None, None, None,\n' % (name,))
  572. WriteDocString(val, file, indent_to_paren)
  573. file.write(indent_to_paren + ')\n\n')
  574. # Value is a function or method
  575. elif callable(val):
  576. try:
  577. seen_vals[val] = 1
  578. except TypeError:
  579. sys.stderr.write("Failed to register %s (may cause duplicates)\n" % str(val))
  580. if last_val is not kNoValue and not callable(last_val):
  581. file.write('\n')
  582. import_line = None
  583. # Trick to get init docs from class level doc where it usually is
  584. if name == '__init__':
  585. doc1 = getattr(val, '__doc__', '')
  586. if doc1 is None:
  587. doc1 = ''
  588. doc2 = getattr(obj, '__doc__', '')
  589. if doc2 is None:
  590. doc2 = ''
  591. args, retval = _GetCallableSignature(doc2 + '\n' + doc1)
  592. elif kIronPython:
  593. args, import_line, retval = GetCallableSignatureIPy(val, obj, name)
  594. else:
  595. args, retval = GetCallableSignature(val)
  596. # Try to fall back on inspect, tho this only works if the module
  597. # is not an extension module or contains some methods defined in Python
  598. if args == '' and inspect is not None:
  599. try:
  600. fval = getattr(val, 'im_func', val)
  601. args = inspect.formatargspec(inspect.getargspec(fval)[0])
  602. args = args[1:-1]
  603. except:
  604. args = ''
  605. if type(obj) == PyType_Type or hasattr(val, 'im_func'):
  606. if len(args) > 0 and string_find(args, 'self') != 0:
  607. args = 'self, ' + args
  608. elif string_find(args, 'self') < 0:
  609. args = 'self'
  610. # Write the definition
  611. file.write(indent + 'def %s(%s):\n' % (name, args))
  612. WriteDocString(val, file, indent + ' ')
  613. if import_line is not None:
  614. file.write(indent + ' %s\n' % import_line)
  615. file.write(indent + ' %s\n\n' % retval)
  616. num_written = num_written + 1
  617. # Value is a constant
  618. elif type(val) in kStringTypes:
  619. use_triple = (string_find(val, '\n') > 0 and string_find(val, '"""') == -1)
  620. val = val.replace('\r\n', '\n')
  621. if use_triple:
  622. for c in val:
  623. if c not in printable_chars:
  624. use_triple = 0
  625. break
  626. if use_triple:
  627. val = '"""%s"""' % str(val)
  628. else:
  629. val = repr(val)
  630. file.write(indent + '%s = %s\n' % (name, val))
  631. num_written = num_written + 1
  632. elif type(val) in kLiteralTypes:
  633. file.write(indent + '%s = %s\n' % (name, str(val)))
  634. num_written = num_written + 1
  635. elif type(val) in kStructureTypes:
  636. if type(val) == kListType:
  637. s = '[]'
  638. elif type(val) == kTupleType:
  639. s = '()'
  640. elif type(val) == kDictType:
  641. s = '{}'
  642. file.write(indent + '%s = %s\n' % (name, s))
  643. num_written = num_written + 1
  644. elif type(val) in kFileTypes:
  645. file.write(indent + '%s = file(__file__)\n' % name)
  646. num_written = num_written + 1
  647. else:
  648. file.write(indent + '%s = None\n' % name)
  649. num_written = num_written + 1
  650. last_val = val
  651. # Add in appropriate overrides
  652. additions = {}
  653. for oname in ValueItems(overrides):
  654. if oname in kOmitTopLevel:
  655. continue
  656. oval = GetValue(overrides, oname, None)
  657. # Class overrides already processed as addition to existing class
  658. # are not shown again
  659. if type(oval) in (kListType, kDictType) or not has_key(seen_vals, oval):
  660. additions[oname] = oval
  661. last_val = oval
  662. if len(additions) > 0:
  663. try:
  664. seen_vals[overrides] = 1
  665. except TypeError:
  666. sys.stderr.write("Failed to register %s (may cause duplicates)\n" % str(overrides))
  667. file.write(indent + '# BEGIN MANUAL OVERRIDES FROM %s\n' % overrides_file)
  668. GenForObject(scope, GetValue(overrides, name, {}), overrides_file, additions, file, seen_vals, indent, use_inspect=1)
  669. file.write(indent + '# END MANUAL OVERRIDES\n')
  670. if last_val is not kNoValue and not callable(last_val):
  671. file.write('\n')
  672. return num_written
  673. def GenPClassForType(scope, overrides, overrides_file, name, obj, file,
  674. seen_vals, indent = '', use_inspect=0):
  675. bases = ""
  676. if inspect is not None and hasattr(inspect, 'getmro'):
  677. try:
  678. baselist = inspect.getmro(obj)
  679. except:
  680. baselist = [obj]
  681. if baselist[0] is obj and len(baselist) > 1:
  682. bases = "(%s)" % baselist[1].__name__
  683. file.write(indent + 'class %s%s:\n' % (name, bases))
  684. WriteDocString(obj, file, indent + kOneLevelIndent)
  685. file.write('\n')
  686. num_written = GenForObject(scope, overrides, overrides_file, obj, file, seen_vals, indent + kOneLevelIndent, use_inspect)
  687. if num_written == 0:
  688. file.write(indent + ' ' + 'pass\n\n')
  689. def ProcessModule(mod_name, magic_code=None, metadata={}, overrides={}, file=None):
  690. if string_find(mod_name, '-') >= 0:
  691. return
  692. if file is None:
  693. file = sys.stdout
  694. seen_vals = {}
  695. if type(overrides) == types.ModuleType:
  696. overrides_file = overrides.__file__
  697. overrides_file = string_join(string_split(overrides_file, os.sep)[-3:], os.sep)
  698. if overrides_file[-1] in ('o', 'c'):
  699. overrides_file = overrides_file[:-1]
  700. else:
  701. overrides_file = None
  702. namespace = {}
  703. if magic_code is not None:
  704. exec(magic_code, namespace)
  705. if not has_key(namespace, mod_name):
  706. exec('import %s' % mod_name, namespace)
  707. else:
  708. # Work-around for bug in 2.1's warning module
  709. if version == (2, 1) and mod_name == 'regex':
  710. namespace['__name__'] = mod_name
  711. try:
  712. exec('import %s' % mod_name, namespace)
  713. except ImportError:
  714. # This case sometimes succeeds when above fails but adding '.' to
  715. # path blindly seems like a bad idea so do it only as a fall-back
  716. sys.path.append('.')
  717. exec('import %s' % mod_name, namespace)
  718. if kIronPython:
  719. sys.stderr.write("Now imported %s\n" % repr(namespace.keys()))
  720. file.write('# AUTO-GENERATED FILE -- DO NOT EDIT\n')
  721. if overrides_file is not None:
  722. file.write('# OVERRIDES FILE: %s\n\n' % overrides_file)
  723. else:
  724. file.write('\n')
  725. components = mod_name.split('.')
  726. mod_name = components[0]
  727. components = components[1:]
  728. mod = namespace.get(mod_name)
  729. while components:
  730. mod = getattr(mod, components[0])
  731. del components[0]
  732. WriteDocString(mod, file, '')
  733. file.write('\n')
  734. GenForObject(['__toplevel__'], overrides, overrides_file, mod, file, seen_vals)
  735. fn = getattr(mod, '__file__', None)
  736. if fn is not None:
  737. try:
  738. fn = os.path.abspath(fn)
  739. except:
  740. metadata['file'] = repr(fn)
  741. else:
  742. metadata['file'] = fn
  743. try:
  744. if os.path.isfile(fn):
  745. s = os.stat(fn)
  746. metadata['modtime'] = s[stat.ST_MTIME]
  747. except:
  748. pass
  749. def DecodeArg(a):
  750. """ If a starts with +, treat any subsequent + as indicator that the
  751. 4 characters following are the hex representation of a code point which
  752. will replace the + and the following 4 chars. Any / will be translated
  753. into os.sep. On win32, always convert to unicode if possible. """
  754. if os.sep != '/':
  755. a = string_replace(a, '/', os.sep)
  756. if a == '' or a[0] != '+':
  757. if sys.platform == 'win32':
  758. try:
  759. return unicode(a)
  760. except:
  761. pass
  762. return a
  763. try:
  764. a = unicode(a)
  765. except:
  766. pass
  767. part_list = string_split(a[1:], '+')
  768. fragments = []
  769. for i, part in enumerate(part_list):
  770. if i == 0:
  771. frag = part
  772. else:
  773. try:
  774. frag = unichr(string.atoi(part[:4], 16))
  775. except:
  776. frag = chr(string.atoi(part[:4], 16))
  777. frag = frag + part[4:]
  778. if frag != '':
  779. fragments.append(frag)
  780. try:
  781. decoded = string_join(fragments, unicode(''))
  782. except:
  783. decoded = string_join(fragments, '')
  784. return decoded
  785. def _PrintUsage():
  786. sys.stdout.write("Usage: %s [options] module-name output-file [python-path] [ld_library_path]\n")
  787. sys.stdout.write("output-file may be '-' to write to stdout. The paths, if given, should be\n")
  788. sys.stdout.write("string separated by os.pathsep (':' or ';' depending on OS). The output-file\n")
  789. sys.stdout.write("is treated as an encoded name if the name begins with a + and any + after\n")
  790. sys.stdout.write("the first is to be followed by a 4 digit hexadecimal number for the code\n")
  791. sys.stdout.write("point at that position in the string\n")
  792. sys.stdout.write("\n")
  793. sys.stdout.write("Valid options:\n")
  794. sys.stdout.write(" --meta-data -- Write meta data file also -- the file name is output-file\n")
  795. sys.stdout.write(" plus '.meta'. This arg is ignored if output-file is '-'\n")
  796. sys.stdout.write(" --magic-code [code] -- Execute given code before attempting to import the \n")
  797. sys.stdout.write(" extension module if importing it alone fails\n")
  798. sys.stdout.write("\n")
  799. sys.stdout.write("The meta data file, if output, contains a cPickle.dump()'ed Python dictionary\n")
  800. sys.stdout.write("with the following fields:\n")
  801. sys.stdout.write(" file -- The module file name\n")
  802. sys.stdout.write(" modtime -- The value of os.stat(file)[stat.M_TIME]\n")
  803. sys.stdout.write("\n")
  804. ##############################################################
  805. # IronPython specifics
  806. class CIronPythonNameSpaceFinder:
  807. def __init__(self):
  808. self.fNamespaces = {}
  809. self.fInspected = set()
  810. import System
  811. self.fNamespaceType = type(System)
  812. def Visit(self, obj, mod_name):
  813. if obj in self.fInspected:
  814. return
  815. self.fInspected.add(obj)
  816. self.fNamespaces[mod_name] = obj
  817. for name in SafeDir(obj):
  818. try:
  819. val = getattr(obj, name)
  820. except:
  821. continue
  822. if isinstance(val, self.fNamespaceType):
  823. dotted_name = '%s.%s' % (mod_name, name)
  824. self.fNamespaces[dotted_name] = val
  825. self.Visit(val, dotted_name)
  826. def GenerateForIronPythonNameSpaces(namespace_list, output_dirname, clr_refs):
  827. import clr
  828. for name in clr_refs:
  829. clr.AddReference(name)
  830. ns_finder = CIronPythonNameSpaceFinder()
  831. for ns_name in namespace_list:
  832. mod = __import__(ns_name)
  833. ns_finder.Visit(mod, ns_name)
  834. sys.stderr.write('%s\n' % repr(ns_finder.fNamespaces.keys()))
  835. sys.stderr.write('%s\n' % repr(len(ns_finder.fNamespaces)))
  836. expanded_list = sorted(ns_finder.fNamespaces.keys())
  837. for ns_name in expanded_list:
  838. kPIPackagesAreBroken = True
  839. if not kPIPackagesAreBroken: # if Wing worked like it should
  840. dirname = os.path.join(output_dirname, *ns_name.split('.'))
  841. if not os.path.exists(dirname):
  842. os.makedirs(dirname)
  843. filename = os.path.join(dirname, '__init__.pi')
  844. else:
  845. filename = os.path.join(output_dirname, ns_name + '.pi')
  846. f = open(filename, 'w')
  847. ProcessModule(ns_name, file=f)
  848. f.close()
  849. ########################################################################
  850. if __name__ == '__main__':
  851. if '--ironpython' in sys.argv:
  852. # CHANGE: Hardwire assembly names to add references and pre-do imports to
  853. # make nested namespaces available as attributes on top level namespace
  854. ref_names = ['System', 'System.Data', 'System.Windows.Forms', 'System.Drawing', 'System.Xml']
  855. output_dir = os.path.abspath('.')
  856. GenerateForIronPythonNameSpaces(['System', 'Microsoft', 'clr'], output_dir, ref_names)
  857. sys.exit(0)
  858. if len(sys.argv) < 3:
  859. _PrintUsage()
  860. sys.exit(1)
  861. write_metadata = 0
  862. if '--meta-data' in sys.argv:
  863. sys.argv.remove('--meta-data')
  864. write_metadata = 1
  865. magic_code = None
  866. if '--magic-code' in sys.argv:
  867. mpos = sys.argv.index('--magic-code')
  868. if len(sys.argv) < mpos + 2:
  869. _PrintUsage()
  870. sys.exit(1)
  871. magic_code = sys.argv[sys.argv.index('--magic-code')+1]
  872. sys.argv.remove('--magic-code')
  873. sys.argv.remove(magic_code)
  874. modname = sys.argv[1]
  875. outfile = sys.argv[2]
  876. if len(sys.argv) >= 4:
  877. for p in string_split(sys.argv[3], os.pathsep):
  878. sys.path.append(os.path.abspath(p))
  879. if len(sys.argv) == 5:
  880. os.environ['LD_LIBRARY_PATH'] = sys.argv[4]
  881. cmd = '"%s" %s "%s" "%s" "%s"' % (sys.executable, sys.argv[0], sys.argv[1], sys.argv[2], sys.argv[3])
  882. sys.exit(os.system(cmd))
  883. if outfile != '-':
  884. outfile = DecodeArg(outfile)
  885. f = open(outfile, 'w')
  886. sys.stdout = f
  887. else:
  888. f = sys.stdout
  889. metadata = {}
  890. ProcessModule(modname, magic_code, metadata, file=f)
  891. if outfile != '-':
  892. sys.stdout = sys.__stdout__
  893. f.close()
  894. # Avoid leaving around lots of empty trash files
  895. if os.stat(outfile)[stat.ST_SIZE] == 0:
  896. try:
  897. sys.stdout.write("generate_pi.py: Removing empty %s\n" % outfile)
  898. os.unlink(outfile)
  899. except:
  900. pass
  901. if write_metadata and outfile != '-':
  902. f = open(outfile + '.meta', 'wb')
  903. if sys.version_info < (3, 0):
  904. import cPickle
  905. cPickle.dump(metadata, f)
  906. else:
  907. import pickle
  908. pickle.dump(metadata, f, 2)
  909. f.close()