reference.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. from __future__ import absolute_import
  2. # Copyright (c) 2010-2019 openpyxl
  3. from itertools import chain
  4. from openpyxl.compat import unicode
  5. from openpyxl.descriptors.serialisable import Serialisable
  6. from openpyxl.descriptors import (
  7. MinMax,
  8. Typed,
  9. String,
  10. Strict,
  11. )
  12. from openpyxl.worksheet.worksheet import Worksheet
  13. from openpyxl.utils import (
  14. get_column_letter,
  15. range_to_tuple,
  16. quote_sheetname
  17. )
  18. class DummyWorksheet:
  19. def __init__(self, title):
  20. self.title = title
  21. class Reference(Strict):
  22. """
  23. Normalise cell range references
  24. """
  25. min_row = MinMax(min=1, max=1000000, expected_type=int)
  26. max_row = MinMax(min=1, max=1000000, expected_type=int)
  27. min_col = MinMax(min=1, max=16384, expected_type=int)
  28. max_col = MinMax(min=1, max=16384, expected_type=int)
  29. range_string = String(allow_none=True)
  30. def __init__(self,
  31. worksheet=None,
  32. min_col=None,
  33. min_row=None,
  34. max_col=None,
  35. max_row=None,
  36. range_string=None
  37. ):
  38. if range_string is not None:
  39. sheetname, boundaries = range_to_tuple(range_string)
  40. min_col, min_row, max_col, max_row = boundaries
  41. worksheet = DummyWorksheet(sheetname)
  42. self.worksheet = worksheet
  43. self.min_col = min_col
  44. self.min_row = min_row
  45. if max_col is None:
  46. max_col = min_col
  47. self.max_col = max_col
  48. if max_row is None:
  49. max_row = min_row
  50. self.max_row = max_row
  51. def __repr__(self):
  52. return unicode(self)
  53. def __str__(self):
  54. fmt = u"{0}!${1}${2}:${3}${4}"
  55. if (self.min_col == self.max_col
  56. and self.min_row == self.max_row):
  57. fmt = u"{0}!${1}${2}"
  58. return fmt.format(self.sheetname,
  59. get_column_letter(self.min_col), self.min_row,
  60. get_column_letter(self.max_col), self.max_row
  61. )
  62. __unicode__ = __str__
  63. def __len__(self):
  64. if self.min_row == self.max_row:
  65. return 1 + self.max_col - self.min_col
  66. return 1 + self.max_row - self.min_row
  67. def __eq__(self, other):
  68. return str(self) == str(other)
  69. @property
  70. def rows(self):
  71. """
  72. Return all rows in the range
  73. """
  74. for row in range(self.min_row, self.max_row+1):
  75. yield Reference(self.worksheet, self.min_col, row, self.max_col, row)
  76. @property
  77. def cols(self):
  78. """
  79. Return all columns in the range
  80. """
  81. for col in range(self.min_col, self.max_col+1):
  82. yield Reference(self.worksheet, col, self.min_row, col, self.max_row)
  83. def pop(self):
  84. """
  85. Return and remove the first cell
  86. """
  87. cell = "{0}{1}".format(get_column_letter(self.min_col), self.min_row)
  88. if self.min_row == self.max_row:
  89. self.min_col += 1
  90. else:
  91. self.min_row += 1
  92. return cell
  93. @property
  94. def sheetname(self):
  95. return quote_sheetname(self.worksheet.title)