Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/io/excel/_calamine.py: 36%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

47 statements  

1from __future__ import annotations 

2 

3from datetime import ( 

4 date, 

5 datetime, 

6 time, 

7 timedelta, 

8) 

9from typing import ( 

10 TYPE_CHECKING, 

11 Any, 

12 TypeAlias, 

13) 

14 

15from pandas.compat._optional import import_optional_dependency 

16 

17from pandas.io.excel._base import BaseExcelReader 

18 

19if TYPE_CHECKING: 

20 from python_calamine import ( 

21 CalamineSheet, 

22 CalamineWorkbook, 

23 ) 

24 

25 from pandas._typing import ( 

26 FilePath, 

27 NaTType, 

28 ReadBuffer, 

29 Scalar, 

30 StorageOptions, 

31 ) 

32 

33_CellValue: TypeAlias = int | float | str | bool | time | date | datetime | timedelta 

34 

35 

36class CalamineReader(BaseExcelReader["CalamineWorkbook"]): 

37 def __init__( 

38 self, 

39 filepath_or_buffer: FilePath | ReadBuffer[bytes], 

40 storage_options: StorageOptions | None = None, 

41 engine_kwargs: dict | None = None, 

42 ) -> None: 

43 """ 

44 Reader using calamine engine (xlsx/xls/xlsb/ods). 

45 

46 Parameters 

47 ---------- 

48 filepath_or_buffer : str, path to be parsed or 

49 an open readable stream. 

50 storage_options : dict, optional 

51 Extra options that make sense for a particular storage connection, e.g. 

52 host, port, username, password, etc. For HTTP(S) URLs the key-value pairs 

53 are forwarded to ``urllib.request.Request`` as header options. For other 

54 URLs (e.g. starting with "s3://", and "gcs://") the key-value pairs are 

55 forwarded to ``fsspec.open``. Please see ``fsspec`` and ``urllib`` for more 

56 details, and for more examples on storage options refer `here 

57 <https://pandas.pydata.org/docs/user_guide/io.html? 

58 highlight=storage_options#reading-writing-remote-files>`_. 

59 engine_kwargs : dict, optional 

60 Arbitrary keyword arguments passed to excel engine. 

61 """ 

62 import_optional_dependency("python_calamine") 

63 super().__init__( 

64 filepath_or_buffer, 

65 storage_options=storage_options, 

66 engine_kwargs=engine_kwargs, 

67 ) 

68 

69 @property 

70 def _workbook_class(self) -> type[CalamineWorkbook]: 

71 from python_calamine import CalamineWorkbook 

72 

73 return CalamineWorkbook 

74 

75 def load_workbook( 

76 self, filepath_or_buffer: FilePath | ReadBuffer[bytes], engine_kwargs: Any 

77 ) -> CalamineWorkbook: 

78 from python_calamine import load_workbook 

79 

80 return load_workbook( 

81 filepath_or_buffer, 

82 **engine_kwargs, 

83 ) 

84 

85 @property 

86 def sheet_names(self) -> list[str]: 

87 from python_calamine import SheetTypeEnum 

88 

89 return [ 

90 sheet.name 

91 for sheet in self.book.sheets_metadata 

92 if sheet.typ == SheetTypeEnum.WorkSheet 

93 ] 

94 

95 def get_sheet_by_name(self, name: str) -> CalamineSheet: 

96 self.raise_if_bad_sheet_by_name(name) 

97 return self.book.get_sheet_by_name(name) 

98 

99 def get_sheet_by_index(self, index: int) -> CalamineSheet: 

100 self.raise_if_bad_sheet_by_index(index) 

101 return self.book.get_sheet_by_index(index) 

102 

103 def get_sheet_data( 

104 self, sheet: CalamineSheet, file_rows_needed: int | None = None 

105 ) -> list[list[Scalar | NaTType | time]]: 

106 def _convert_cell(value: _CellValue) -> Scalar | NaTType | time: 

107 if isinstance(value, float): 

108 val = int(value) 

109 if val == value: 

110 return val 

111 else: 

112 return value 

113 elif isinstance(value, (datetime, timedelta)): 

114 # Return as-is to match openpyxl behavior (GH#59186) 

115 return value 

116 elif isinstance(value, date): 

117 # Convert date to datetime to match openpyxl behavior (GH#59186) 

118 return datetime(value.year, value.month, value.day) 

119 elif isinstance(value, time): 

120 return value 

121 

122 return value 

123 

124 rows: list[list[_CellValue]] = sheet.to_python( 

125 skip_empty_area=False, nrows=file_rows_needed 

126 ) 

127 data = [[_convert_cell(cell) for cell in row] for row in rows] 

128 

129 return data