child.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. from __future__ import absolute_import
  2. # Copyright (c) 2010-2019 openpyxl
  3. import re
  4. import warnings
  5. from openpyxl.compat import unicode, safe_repr
  6. from openpyxl.worksheet.header_footer import HeaderFooter
  7. """
  8. Base class for worksheets, chartsheets, etc. that can be added to workbooks
  9. """
  10. INVALID_TITLE_REGEX = re.compile(r'[\\*?:/\[\]]')
  11. def avoid_duplicate_name(names, value):
  12. """
  13. Naive check to see whether name already exists.
  14. If name does exist suggest a name using an incrementer
  15. Duplicates are case insensitive
  16. """
  17. # Check for an absolute match in which case we need to find an alternative
  18. match = [n for n in names if n.lower() == value.lower()]
  19. if match:
  20. names = u",".join(names)
  21. sheet_title_regex = re.compile(r"(?P<title>%s)(?P<count>\d*),?" % re.escape(value), re.I)
  22. matches = sheet_title_regex.findall(names)
  23. if matches:
  24. # use name, but append with the next highest integer
  25. counts = [int(idx) for (t, idx) in matches if idx.isdigit()]
  26. highest = 0
  27. if counts:
  28. highest = max(counts)
  29. value = u"{0}{1}".format(value, highest + 1)
  30. return value
  31. class _WorkbookChild(object):
  32. __title = ""
  33. _id = None
  34. _path = "{0}"
  35. _parent = None
  36. _default_title = "Sheet"
  37. def __init__(self, parent=None, title=None):
  38. self._parent = parent
  39. self.title = title or self._default_title
  40. self.HeaderFooter = HeaderFooter()
  41. def __repr__(self):
  42. return '<{0} "{1}">'.format(self.__class__.__name__, safe_repr(self.title))
  43. @property
  44. def parent(self):
  45. return self._parent
  46. @property
  47. def encoding(self):
  48. return self._parent.encoding
  49. @property
  50. def title(self):
  51. return self.__title
  52. @title.setter
  53. def title(self, value):
  54. """
  55. Set a sheet title, ensuring it is valid.
  56. Limited to 31 characters, no special characters.
  57. Duplicate titles will be incremented numerically
  58. """
  59. if not self._parent:
  60. return
  61. if not value:
  62. raise ValueError("Title must have at least one character")
  63. if hasattr(value, "decode"):
  64. if not isinstance(value, unicode):
  65. try:
  66. value = value.decode("ascii")
  67. except UnicodeDecodeError:
  68. raise ValueError("Worksheet titles must be unicode")
  69. m = INVALID_TITLE_REGEX.search(value)
  70. if m:
  71. msg = "Invalid character {0} found in sheet title".format(m.group(0))
  72. raise ValueError(msg)
  73. if self.title is not None and self.title != value:
  74. value = avoid_duplicate_name(self.parent.sheetnames, value)
  75. if len(value) > 31:
  76. warnings.warn("Title is more than 31 characters. Some applications may not be able to read the file")
  77. self.__title = value
  78. @property
  79. def oddHeader(self):
  80. return self.HeaderFooter.oddHeader
  81. @oddHeader.setter
  82. def oddHeader(self, value):
  83. self.HeaderFooter.oddHeader = value
  84. @property
  85. def oddFooter(self):
  86. return self.HeaderFooter.oddFooter
  87. @oddFooter.setter
  88. def oddFooter(self, value):
  89. self.HeaderFooter.oddFooter = value
  90. @property
  91. def evenHeader(self):
  92. return self.HeaderFooter.evenHeader
  93. @evenHeader.setter
  94. def evenHeader(self, value):
  95. self.HeaderFooter.evenHeader = value
  96. @property
  97. def evenFooter(self):
  98. return self.HeaderFooter.evenFooter
  99. @evenFooter.setter
  100. def evenFooter(self, value):
  101. self.HeaderFooter.evenFooter = value
  102. @property
  103. def firstHeader(self):
  104. return self.HeaderFooter.firstHeader
  105. @firstHeader.setter
  106. def firstHeader(self, value):
  107. self.HeaderFooter.firstHeader = value
  108. @property
  109. def firstFooter(self):
  110. return self.HeaderFooter.firstFooter
  111. @firstFooter.setter
  112. def firstFooter(self, value):
  113. self.HeaderFooter.firstFooter = value
  114. @property
  115. def path(self):
  116. return self._path.format(self._id)