reference.py 3.0 KB

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