xlrdnameAPIdemo.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. # -*- coding: cp1252 -*-
  2. ##
  3. # Module/script example of the xlrd API for extracting information
  4. # about named references, named constants, etc.
  5. #
  6. # <p>Copyright © 2006 Stephen John Machin, Lingfo Pty Ltd</p>
  7. # <p>This module is part of the xlrd package, which is released under a BSD-style licence.</p>
  8. ##
  9. from __future__ import print_function
  10. import xlrd
  11. from xlrd.timemachine import REPR
  12. import sys
  13. import glob
  14. def scope_as_string(book, scope):
  15. if 0 <= scope < book.nsheets:
  16. return "sheet #%d (%r)" % (scope, REPR(book.sheet_names()[scope]))
  17. if scope == -1:
  18. return "Global"
  19. if scope == -2:
  20. return "Macro/VBA"
  21. return "Unknown scope value (%r)" % REPR(scope)
  22. def do_scope_query(book, scope_strg, show_contents=0, f=sys.stdout):
  23. try:
  24. qscope = int(scope_strg)
  25. except ValueError:
  26. if scope_strg == "*":
  27. qscope = None # means "all'
  28. else:
  29. # so assume it's a sheet name ...
  30. qscope = book.sheet_names().index(scope_strg)
  31. print("%r => %d" % (scope_strg, qscope), file=f)
  32. for nobj in book.name_obj_list:
  33. if qscope is None or nobj.scope == qscope:
  34. show_name_object(book, nobj, show_contents, f)
  35. def show_name_details(book, name, show_contents=0, f=sys.stdout):
  36. """
  37. book -- Book object obtained from xlrd.open_workbook().
  38. name -- The name that's being investigated.
  39. show_contents -- 0: Don't; 1: Non-empty cells only; 2: All cells
  40. f -- Open output file handle.
  41. """
  42. name_lcase = name.lower() # Excel names are case-insensitive.
  43. nobj_list = book.name_map.get(name_lcase)
  44. if not nobj_list:
  45. print("%r: unknown name" % name, file=f)
  46. return
  47. for nobj in nobj_list:
  48. show_name_object(book, nobj, show_contents, f)
  49. def show_name_details_in_scope(
  50. book, name, scope_strg, show_contents=0, f=sys.stdout,
  51. ):
  52. try:
  53. scope = int(scope_strg)
  54. except ValueError:
  55. # so assume it's a sheet name ...
  56. scope = book.sheet_names().index(scope_strg)
  57. print("%r => %d" % (scope_strg, scope), file=f)
  58. name_lcase = name.lower() # Excel names are case-insensitive.
  59. while 1:
  60. nobj = book.name_and_scope_map.get((name_lcase, scope))
  61. if nobj:
  62. break
  63. print("Name %s not found in scope %d" % (REPR(name), scope), file=f)
  64. if scope == -1:
  65. return
  66. scope = -1 # Try again with global scope
  67. print("Name %s found in scope %d" % (REPR(name), scope), file=f)
  68. show_name_object(book, nobj, show_contents, f)
  69. def showable_cell_value(celltype, cellvalue, datemode):
  70. if celltype == xlrd.XL_CELL_DATE:
  71. try:
  72. showval = xlrd.xldate_as_tuple(cellvalue, datemode)
  73. except xlrd.XLDateError as e:
  74. showval = "%s:%s" % (type(e).__name__, e)
  75. elif celltype == xlrd.XL_CELL_ERROR:
  76. showval = xlrd.error_text_from_code.get(
  77. cellvalue, '<Unknown error code 0x%02x>' % cellvalue)
  78. else:
  79. showval = cellvalue
  80. return showval
  81. def show_name_object(book, nobj, show_contents=0, f=sys.stdout):
  82. print("\nName: %s, scope: %s (%s)" \
  83. % (REPR(nobj.name), REPR(nobj.scope), scope_as_string(book, nobj.scope)), file=f)
  84. res = nobj.result
  85. print("Formula eval result: %s" % REPR(res), file=f)
  86. if res is None:
  87. return
  88. # result should be an instance of the Operand class
  89. kind = res.kind
  90. value = res.value
  91. if kind >= 0:
  92. # A scalar, or unknown ... you've seen all there is to see.
  93. pass
  94. elif kind == xlrd.oREL:
  95. # A list of Ref3D objects representing *relative* ranges
  96. for i in range(len(value)):
  97. ref3d = value[i]
  98. print("Range %d: %s ==> %s"% (i, REPR(ref3d.coords), REPR(xlrd.rangename3drel(book, ref3d))), file=f)
  99. elif kind == xlrd.oREF:
  100. # A list of Ref3D objects
  101. for i in range(len(value)):
  102. ref3d = value[i]
  103. print("Range %d: %s ==> %s"% (i, REPR(ref3d.coords), REPR(xlrd.rangename3d(book, ref3d))), file=f)
  104. if not show_contents:
  105. continue
  106. datemode = book.datemode
  107. for shx in range(ref3d.shtxlo, ref3d.shtxhi):
  108. sh = book.sheet_by_index(shx)
  109. print(" Sheet #%d (%s)" % (shx, sh.name), file=f)
  110. rowlim = min(ref3d.rowxhi, sh.nrows)
  111. collim = min(ref3d.colxhi, sh.ncols)
  112. for rowx in range(ref3d.rowxlo, rowlim):
  113. for colx in range(ref3d.colxlo, collim):
  114. cty = sh.cell_type(rowx, colx)
  115. if cty == xlrd.XL_CELL_EMPTY and show_contents == 1:
  116. continue
  117. cval = sh.cell_value(rowx, colx)
  118. sval = showable_cell_value(cty, cval, datemode)
  119. print(" (%3d,%3d) %-5s: %s"
  120. % (rowx, colx, xlrd.cellname(rowx, colx), REPR(sval)), file=f)
  121. if __name__ == "__main__":
  122. def usage():
  123. text = """
  124. usage: xlrdnameAIPdemo.py glob_pattern name scope show_contents
  125. where:
  126. "glob_pattern" designates a set of files
  127. "name" is a name or '*' (all names)
  128. "scope" is -1 (global) or a sheet number
  129. or a sheet name or * (all scopes)
  130. "show_contents" is one of 0 (no show),
  131. 1 (only non-empty cells), or 2 (all cells)
  132. Examples (script name and glob_pattern arg omitted for brevity)
  133. [Searching through book.name_obj_list]
  134. * * 0 lists all names
  135. * * 1 lists all names, showing referenced non-empty cells
  136. * 1 0 lists all names local to the 2nd sheet
  137. * Northern 0 lists all names local to the 'Northern' sheet
  138. * -1 0 lists all names with global scope
  139. [Initial direct access through book.name_map]
  140. Sales * 0 lists all occurrences of "Sales" in any scope
  141. [Direct access through book.name_and_scope_map]
  142. Revenue -1 0 checks if "Revenue" exists in global scope
  143. """
  144. sys.stdout.write(text)
  145. if len(sys.argv) != 5:
  146. usage()
  147. sys.exit(0)
  148. arg_pattern = sys.argv[1] # glob pattern e.g. "foo*.xls"
  149. arg_name = sys.argv[2] # see below
  150. arg_scope = sys.argv[3] # see below
  151. arg_show_contents = int(sys.argv[4]) # 0: no show, 1: only non-empty cells,
  152. # 2: all cells
  153. for fname in glob.glob(arg_pattern):
  154. book = xlrd.open_workbook(fname)
  155. if arg_name == "*":
  156. # Examine book.name_obj_list to find all names
  157. # in a given scope ("*" => all scopes)
  158. do_scope_query(book, arg_scope, arg_show_contents)
  159. elif arg_scope == "*":
  160. # Using book.name_map to find all usage of a name.
  161. show_name_details(book, arg_name, arg_show_contents)
  162. else:
  163. # Using book.name_and_scope_map to find which if any instances
  164. # of a name are visible in the given scope, which can be supplied
  165. # as -1 (global) or a sheet number or a sheet name.
  166. show_name_details_in_scope(book, arg_name, arg_scope, arg_show_contents)