xlsxturbo 0.10.1__cp38-abi3-macosx_11_0_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
xlsxturbo/__init__.py ADDED
@@ -0,0 +1,4 @@
1
+ # Re-export from the Rust extension
2
+ from .xlsxturbo import csv_to_xlsx, df_to_xlsx, dfs_to_xlsx, version, __version__
3
+
4
+ __all__ = ["csv_to_xlsx", "df_to_xlsx", "dfs_to_xlsx", "version", "__version__"]
xlsxturbo/__init__.pyi ADDED
@@ -0,0 +1,271 @@
1
+ """Type stubs for xlsxturbo"""
2
+
3
+ from typing import Literal, TypedDict
4
+
5
+ DateOrder = Literal["auto", "mdy", "us", "dmy", "eu", "european"]
6
+ ValidationType = Literal["list", "whole_number", "decimal", "text_length"]
7
+
8
+ class HeaderFormat(TypedDict, total=False):
9
+ """Header cell formatting options. All fields are optional."""
10
+ bold: bool
11
+ italic: bool
12
+ font_color: str # '#RRGGBB' or named color (white, black, red, blue, etc.)
13
+ bg_color: str # '#RRGGBB' or named color
14
+ font_size: float
15
+ underline: bool
16
+
17
+ class ColumnFormat(TypedDict, total=False):
18
+ """Column cell formatting options. All fields are optional."""
19
+ bold: bool
20
+ italic: bool
21
+ font_color: str # '#RRGGBB' or named color (white, black, red, blue, etc.)
22
+ bg_color: str # '#RRGGBB' or named color
23
+ font_size: float
24
+ underline: bool
25
+ num_format: str # Excel number format string, e.g. '0.00', '#,##0', '0.00%'
26
+ border: bool # Add thin border around cells
27
+
28
+ class ConditionalFormat(TypedDict, total=False):
29
+ """Conditional formatting options for a column. 'type' is required.
30
+
31
+ Supported types:
32
+ - '2_color_scale': Gradient from min_color to max_color
33
+ - '3_color_scale': Gradient with min_color, mid_color, max_color
34
+ - 'data_bar': In-cell bar chart
35
+ - 'icon_set': Traffic lights, arrows, or other icons
36
+ """
37
+ type: str # Required: '2_color_scale', '3_color_scale', 'data_bar', 'icon_set'
38
+ # For color scales:
39
+ min_color: str # '#RRGGBB' or named color for minimum value
40
+ mid_color: str # '#RRGGBB' or named color for midpoint (3_color_scale only)
41
+ max_color: str # '#RRGGBB' or named color for maximum value
42
+ # For data bars:
43
+ bar_color: str # '#RRGGBB' or named color for the bar fill
44
+ border_color: str # '#RRGGBB' or named color for bar border
45
+ solid: bool # True for solid fill, False for gradient (default)
46
+ direction: str # 'left_to_right', 'right_to_left', or 'context' (default)
47
+ # For icon sets:
48
+ icon_type: str # '3_arrows', '3_traffic_lights', '3_flags', '4_arrows', '5_arrows', etc. (see README for full list)
49
+ reverse: bool # Reverse icon order
50
+ icons_only: bool # Show only icons, hide values
51
+
52
+ class CommentOptions(TypedDict, total=False):
53
+ """Options for cell comments/notes.
54
+
55
+ Note: 'text' is required at runtime but TypedDict doesn't enforce this.
56
+ """
57
+ text: str # The comment text (required at runtime)
58
+ author: str # Author name for the comment
59
+
60
+ class ValidationOptions(TypedDict, total=False):
61
+ """Data validation options for a column. 'type' is required.
62
+
63
+ Supported types:
64
+ - 'list': Dropdown with specified values
65
+ - 'whole_number': Integer between min and max
66
+ - 'decimal': Decimal number between min and max
67
+ - 'text_length': Text length between min and max
68
+ """
69
+ type: ValidationType # Required: validation type
70
+ values: list[str] # For 'list' type: dropdown options
71
+ min: int | float # For number/text_length: minimum value
72
+ max: int | float # For number/text_length: maximum value
73
+ input_title: str # Title for input prompt
74
+ input_message: str # Message for input prompt
75
+ error_title: str # Title for error message
76
+ error_message: str # Message for error message
77
+
78
+ class RichTextFormat(TypedDict, total=False):
79
+ """Format options for a rich text segment."""
80
+ bold: bool
81
+ italic: bool
82
+ font_color: str # '#RRGGBB' or named color
83
+ bg_color: str # '#RRGGBB' or named color
84
+ font_size: float
85
+ underline: bool
86
+
87
+ class ImageOptions(TypedDict, total=False):
88
+ """Options for embedding images.
89
+
90
+ Note: 'path' is required at runtime but TypedDict doesn't enforce this.
91
+ """
92
+ path: str # Path to image file - PNG, JPEG, GIF, BMP (required at runtime)
93
+ scale_width: float # Scale factor for width (1.0 = original)
94
+ scale_height: float # Scale factor for height (1.0 = original)
95
+ alt_text: str # Alternative text for accessibility
96
+
97
+ class SheetOptions(TypedDict, total=False):
98
+ """Per-sheet options for dfs_to_xlsx. All fields are optional."""
99
+ header: bool
100
+ autofit: bool
101
+ table_style: str | None
102
+ freeze_panes: bool
103
+ column_widths: dict[int | str, float] | None # Keys: int index or '_all'
104
+ row_heights: dict[int, float] | None
105
+ table_name: str | None
106
+ header_format: HeaderFormat | None
107
+ column_formats: dict[str, ColumnFormat] | None # Pattern -> format. Patterns: 'prefix*', '*suffix', '*contains*', exact
108
+ conditional_formats: dict[str, ConditionalFormat] | None # Column name/pattern -> conditional format config
109
+ formula_columns: dict[str, str] | None # Column name -> Excel formula template with {row} placeholder
110
+ merged_ranges: list[tuple[str, str] | tuple[str, str, HeaderFormat]] | None # (range, text) or (range, text, format)
111
+ hyperlinks: list[tuple[str, str] | tuple[str, str, str]] | None # (cell, url) or (cell, url, display_text)
112
+ comments: dict[str, str | CommentOptions] | None # Cell ref -> comment text or options
113
+ validations: dict[str, ValidationOptions] | None # Column name/pattern -> validation options
114
+ rich_text: dict[str, list[tuple[str, RichTextFormat] | str]] | None # Cell ref -> list of (text, format) or plain text
115
+ images: dict[str, str | ImageOptions] | None # Cell ref -> image path or options
116
+
117
+ def csv_to_xlsx(
118
+ input_path: str,
119
+ output_path: str,
120
+ sheet_name: str = "Sheet1",
121
+ parallel: bool = False,
122
+ date_order: DateOrder = "auto",
123
+ ) -> tuple[int, int]:
124
+ """
125
+ Convert a CSV file to XLSX format with automatic type detection.
126
+
127
+ Args:
128
+ input_path: Path to the input CSV file
129
+ output_path: Path for the output XLSX file
130
+ sheet_name: Name of the worksheet (default: "Sheet1")
131
+ parallel: Use multi-core parallel processing (default: False).
132
+ Faster for large files (100K+ rows) but uses more memory.
133
+ date_order: Date parsing order for ambiguous dates like "01-02-2024".
134
+ "auto" - ISO first, then European (DMY), then US (MDY)
135
+ "mdy" or "us" - US format: 01-02-2024 = January 2nd
136
+ "dmy" or "eu" - European format: 01-02-2024 = February 1st
137
+
138
+ Returns:
139
+ Tuple of (rows, columns) written to the Excel file
140
+
141
+ Raises:
142
+ ValueError: If the conversion fails
143
+ """
144
+ ...
145
+
146
+ def df_to_xlsx(
147
+ df: object,
148
+ output_path: str,
149
+ sheet_name: str = "Sheet1",
150
+ header: bool = True,
151
+ autofit: bool = False,
152
+ table_style: str | None = None,
153
+ freeze_panes: bool = False,
154
+ column_widths: dict[int | str, float] | None = None,
155
+ table_name: str | None = None,
156
+ header_format: HeaderFormat | None = None,
157
+ row_heights: dict[int, float] | None = None,
158
+ constant_memory: bool = False,
159
+ column_formats: dict[str, ColumnFormat] | None = None,
160
+ conditional_formats: dict[str, ConditionalFormat] | None = None,
161
+ formula_columns: dict[str, str] | None = None,
162
+ merged_ranges: list[tuple[str, str] | tuple[str, str, HeaderFormat]] | None = None,
163
+ hyperlinks: list[tuple[str, str] | tuple[str, str, str]] | None = None,
164
+ comments: dict[str, str | CommentOptions] | None = None,
165
+ validations: dict[str, ValidationOptions] | None = None,
166
+ rich_text: dict[str, list[tuple[str, RichTextFormat] | str]] | None = None,
167
+ images: dict[str, str | ImageOptions] | None = None,
168
+ ) -> tuple[int, int]:
169
+ """
170
+ Convert a pandas or polars DataFrame to XLSX format.
171
+
172
+ Args:
173
+ df: pandas DataFrame or polars DataFrame to export
174
+ output_path: Path for the output XLSX file
175
+ sheet_name: Name of the worksheet (default: "Sheet1")
176
+ header: Include column names as header row (default: True)
177
+ autofit: Automatically adjust column widths to fit content (default: False)
178
+ table_style: Apply Excel table formatting (default: None).
179
+ Styles: "Light1"-"Light21", "Medium1"-"Medium28", "Dark1"-"Dark11", "None".
180
+ freeze_panes: Freeze the header row for easier scrolling (default: False)
181
+ column_widths: Dict mapping column index to width. Use '_all' to cap all columns.
182
+ row_heights: Dict mapping row index to height in points.
183
+ constant_memory: Use streaming mode for minimal RAM usage (default: False).
184
+ table_name: Custom name for the Excel table (requires table_style).
185
+ header_format: Dict of header cell formatting options.
186
+ column_formats: Dict mapping column name patterns to format options.
187
+ Patterns: 'prefix*', '*suffix', '*contains*', or exact match.
188
+ First matching pattern wins (order preserved).
189
+ conditional_formats: Dict mapping column names to conditional format configs.
190
+ Supported types: '2_color_scale', '3_color_scale', 'data_bar', 'icon_set'.
191
+ Example: {'score': {'type': '2_color_scale', 'min_color': '#FF0000', 'max_color': '#00FF00'}}
192
+ formula_columns: Dict mapping new column names to Excel formula templates.
193
+ Use {row} placeholder for the current row number (1-based Excel row).
194
+ Example: {'Total': '=A{row}+B{row}', 'Percentage': '=C{row}/D{row}*100'}
195
+ merged_ranges: List of (range, text) or (range, text, format) tuples to merge cells.
196
+ Range uses Excel notation (e.g., 'A1:D1'). Format uses HeaderFormat options.
197
+ Example: [('A1:B1', 'Title'), ('C1:D1', 'Subtitle', {'bold': True})]
198
+ hyperlinks: List of (cell, url) or (cell, url, display_text) tuples to add clickable links.
199
+ Cell uses Excel notation (e.g., 'A1'). Display text is optional.
200
+ Example: [('A2', 'https://example.com'), ('B2', 'https://google.com', 'Google')]
201
+ comments: Dict mapping cell refs to comment text or CommentOptions.
202
+ Example: {'A1': 'Simple note'} or {'A1': {'text': 'Note', 'author': 'John'}}
203
+ validations: Dict mapping column name/pattern to data validation config.
204
+ Types: 'list' (dropdown), 'whole_number', 'decimal', 'text_length'.
205
+ Example: {'Status': {'type': 'list', 'values': ['Open', 'Closed']}}
206
+ rich_text: Dict mapping cell refs to list of (text, format) tuples or plain strings.
207
+ Example: {'A1': [('Bold', {'bold': True}), ' normal text']}
208
+ images: Dict mapping cell refs to image path or ImageOptions.
209
+ Example: {'B5': 'logo.png'} or {'B5': {'path': 'logo.png', 'scale_width': 0.5}}
210
+ """
211
+ ...
212
+
213
+ def dfs_to_xlsx(
214
+ sheets: list[tuple[object, str] | tuple[object, str, SheetOptions]],
215
+ output_path: str,
216
+ header: bool = True,
217
+ autofit: bool = False,
218
+ table_style: str | None = None,
219
+ freeze_panes: bool = False,
220
+ column_widths: dict[int | str, float] | None = None,
221
+ table_name: str | None = None,
222
+ header_format: HeaderFormat | None = None,
223
+ row_heights: dict[int, float] | None = None,
224
+ constant_memory: bool = False,
225
+ column_formats: dict[str, ColumnFormat] | None = None,
226
+ conditional_formats: dict[str, ConditionalFormat] | None = None,
227
+ formula_columns: dict[str, str] | None = None,
228
+ merged_ranges: list[tuple[str, str] | tuple[str, str, HeaderFormat]] | None = None,
229
+ hyperlinks: list[tuple[str, str] | tuple[str, str, str]] | None = None,
230
+ comments: dict[str, str | CommentOptions] | None = None,
231
+ validations: dict[str, ValidationOptions] | None = None,
232
+ rich_text: dict[str, list[tuple[str, RichTextFormat] | str]] | None = None,
233
+ images: dict[str, str | ImageOptions] | None = None,
234
+ ) -> list[tuple[int, int]]:
235
+ """
236
+ Write multiple DataFrames to separate sheets in a single workbook.
237
+
238
+ Args:
239
+ sheets: List of (DataFrame, sheet_name) or (DataFrame, sheet_name, options) tuples.
240
+ output_path: Path for the output XLSX file
241
+ header: Include column names as header row (default: True)
242
+ autofit: Automatically adjust column widths (default: False)
243
+ table_style: Apply Excel table formatting (default: None).
244
+ freeze_panes: Freeze the header row (default: False)
245
+ column_widths: Dict mapping column index to width. Use '_all' to cap all columns.
246
+ row_heights: Dict mapping row index to height in points.
247
+ constant_memory: Use streaming mode (default: False).
248
+ table_name: Custom name for Excel tables (requires table_style).
249
+ header_format: Dict of header cell formatting options.
250
+ column_formats: Dict mapping column name patterns to format options.
251
+ Patterns: 'prefix*', '*suffix', '*contains*', or exact match.
252
+ conditional_formats: Dict mapping column names to conditional format configs.
253
+ Supported types: '2_color_scale', '3_color_scale', 'data_bar', 'icon_set'.
254
+ formula_columns: Dict mapping new column names to Excel formula templates.
255
+ Use {row} placeholder for the current row number (1-based Excel row).
256
+ merged_ranges: List of (range, text) or (range, text, format) tuples to merge cells.
257
+ Range uses Excel notation (e.g., 'A1:D1'). Format uses HeaderFormat options.
258
+ hyperlinks: List of (cell, url) or (cell, url, display_text) tuples to add clickable links.
259
+ Cell uses Excel notation (e.g., 'A1'). Display text is optional.
260
+ comments: Dict mapping cell refs to comment text or CommentOptions.
261
+ validations: Dict mapping column name/pattern to data validation config.
262
+ rich_text: Dict mapping cell refs to list of (text, format) tuples or plain strings.
263
+ images: Dict mapping cell refs to image path or ImageOptions.
264
+ """
265
+ ...
266
+
267
+ def version() -> str:
268
+ """Get the version of the xlsxturbo library."""
269
+ ...
270
+
271
+ __version__: str
Binary file
@@ -0,0 +1,878 @@
1
+ Metadata-Version: 2.4
2
+ Name: xlsxturbo
3
+ Version: 0.10.1
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Intended Audience :: Developers
6
+ Classifier: Intended Audience :: Science/Research
7
+ Classifier: License :: OSI Approved :: MIT License
8
+ Classifier: Operating System :: OS Independent
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.8
11
+ Classifier: Programming Language :: Python :: 3.9
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Rust
16
+ Classifier: Topic :: Office/Business :: Financial :: Spreadsheet
17
+ Classifier: Topic :: Scientific/Engineering
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Requires-Dist: pytest ; extra == 'dev'
20
+ Requires-Dist: pandas ; extra == 'dev'
21
+ Requires-Dist: polars ; extra == 'dev'
22
+ Requires-Dist: openpyxl ; extra == 'dev'
23
+ Provides-Extra: dev
24
+ License-File: LICENSE
25
+ Summary: High-performance Excel writer with automatic type detection (pandas, polars, CSV)
26
+ Keywords: excel,xlsx,csv,converter,performance,rust
27
+ License: MIT
28
+ Requires-Python: >=3.8
29
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
30
+ Project-URL: Homepage, https://github.com/tstone-1/xlsxturbo
31
+ Project-URL: Issues, https://github.com/tstone-1/xlsxturbo/issues
32
+ Project-URL: Repository, https://github.com/tstone-1/xlsxturbo
33
+
34
+ # xlsxturbo
35
+
36
+ High-performance Excel writer with automatic type detection. Written in Rust, usable from Python.
37
+
38
+ ## Features
39
+
40
+ - **Direct DataFrame support** for pandas and polars
41
+ - **Excel tables** - filterable tables with 61 built-in styles (banded rows, autofilter)
42
+ - **Conditional formatting** - color scales, data bars, icon sets for visual data analysis
43
+ - **Formula columns** - add calculated columns with Excel formulas
44
+ - **Merged cells** - merge cell ranges for headers and titles
45
+ - **Hyperlinks** - add clickable links to cells
46
+ - **Comments/Notes** - add cell annotations with optional author
47
+ - **Data validation** - dropdowns, number ranges, text length constraints
48
+ - **Rich text** - multiple formats within a single cell
49
+ - **Images** - embed PNG, JPEG, GIF, BMP in cells
50
+ - **Auto-fit columns** - automatically adjust column widths to fit content
51
+ - **Custom column widths** - set specific widths per column or cap all with _all
52
+ - **Header styling** - bold, colors, font size for header row
53
+ - **Named tables** - set custom table names
54
+ - **Custom row heights** - set specific heights per row
55
+ - **Freeze panes** - freeze header row for easier scrolling
56
+ - **Multi-sheet workbooks** - write multiple DataFrames to one file
57
+ - **Per-sheet options** - override settings per sheet in multi-sheet workbooks
58
+ - **Constant memory mode** - minimize RAM usage for very large files
59
+ - **Parallel CSV processing** - optional multi-core parsing for large files
60
+ - **Automatic type detection** from CSV strings and Python objects:
61
+ - Integers and floats → Excel numbers
62
+ - `true`/`false` → Excel booleans
63
+ - Dates (`2024-01-15`, `15/01/2024`, etc.) → Excel dates with formatting
64
+ - Datetimes (ISO 8601) → Excel datetimes
65
+ - `NaN`/`Inf` → Empty cells (graceful handling)
66
+ - Everything else → Text
67
+ - **~6x faster** than pandas + openpyxl (see [benchmarks](#performance))
68
+ - **Memory efficient** - streams data with 1MB buffer
69
+ - Available as both **Python library** and **CLI tool**
70
+
71
+ ## Installation
72
+
73
+ ```bash
74
+ pip install xlsxturbo
75
+ ```
76
+
77
+ Or build from source:
78
+
79
+ ```bash
80
+ pip install maturin
81
+ maturin develop --release
82
+ ```
83
+
84
+ ## Python Usage
85
+
86
+ ### DataFrame Export (pandas/polars)
87
+
88
+ ```python
89
+ import xlsxturbo
90
+ import pandas as pd
91
+
92
+ # Create a DataFrame
93
+ df = pd.DataFrame({
94
+ 'name': ['Alice', 'Bob'],
95
+ 'age': [30, 25],
96
+ 'salary': [50000.50, 60000.75],
97
+ 'active': [True, False]
98
+ })
99
+
100
+ # Export to XLSX (preserves types: int, float, bool, date, datetime)
101
+ rows, cols = xlsxturbo.df_to_xlsx(df, "output.xlsx")
102
+ print(f"Wrote {rows} rows and {cols} columns")
103
+
104
+ # Works with polars too!
105
+ import polars as pl
106
+ df_polars = pl.DataFrame({'x': [1, 2, 3], 'y': [4.0, 5.0, 6.0]})
107
+ xlsxturbo.df_to_xlsx(df_polars, "polars_output.xlsx", sheet_name="Data")
108
+ ```
109
+
110
+ ### Excel Tables with Styling
111
+
112
+ ```python
113
+ import xlsxturbo
114
+ import pandas as pd
115
+
116
+ df = pd.DataFrame({
117
+ 'Product': ['Widget A', 'Widget B', 'Widget C'],
118
+ 'Price': [19.99, 29.99, 39.99],
119
+ 'Quantity': [100, 75, 50],
120
+ })
121
+
122
+ # Create a styled Excel table with autofilter, banded rows, and auto-fit columns
123
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
124
+ table_style="Medium9", # Excel's default table style
125
+ autofit=True, # Fit column widths to content
126
+ freeze_panes=True # Freeze header row for scrolling
127
+ )
128
+
129
+ # Available styles: Light1-Light21, Medium1-Medium28, Dark1-Dark11
130
+ xlsxturbo.df_to_xlsx(df, "dark_table.xlsx", table_style="Dark1", autofit=True)
131
+ ```
132
+
133
+ ### Custom Column Widths and Row Heights
134
+
135
+ ```python
136
+ import xlsxturbo
137
+ import pandas as pd
138
+
139
+ df = pd.DataFrame({
140
+ 'Name': ['Alice', 'Bob', 'Charlie'],
141
+ 'Department': ['Engineering', 'Marketing', 'Sales'],
142
+ 'Salary': [75000, 65000, 55000]
143
+ })
144
+
145
+ # Set specific column widths (column index -> width in characters)
146
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
147
+ column_widths={0: 20, 1: 25, 2: 15}
148
+ )
149
+
150
+ # Set specific row heights (row index -> height in points)
151
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
152
+ row_heights={0: 25} # Make header row taller
153
+ )
154
+
155
+ # Combine with other options
156
+ xlsxturbo.df_to_xlsx(df, "styled.xlsx",
157
+ table_style="Medium9",
158
+ freeze_panes=True,
159
+ column_widths={0: 20, 1: 30, 2: 15},
160
+ row_heights={0: 22}
161
+ )
162
+ ```
163
+
164
+ ### Global Column Width Cap
165
+
166
+ Use `column_widths={'_all': value}` to cap all columns at a maximum width:
167
+
168
+ ```python
169
+ import xlsxturbo
170
+ import pandas as pd
171
+
172
+ df = pd.DataFrame({
173
+ 'Name': ['Alice', 'Bob'],
174
+ 'VeryLongDescription': ['A' * 100, 'B' * 100],
175
+ 'Score': [95, 87]
176
+ })
177
+
178
+ # Cap all columns at 30 characters
179
+ xlsxturbo.df_to_xlsx(df, "capped.xlsx", column_widths={'_all': 30})
180
+
181
+ # Mix specific widths with global cap (specific overrides '_all')
182
+ xlsxturbo.df_to_xlsx(df, "mixed.xlsx", column_widths={0: 15, '_all': 30})
183
+
184
+ # Autofit with cap: fit content, but never exceed 25 characters
185
+ xlsxturbo.df_to_xlsx(df, "fitted.xlsx", autofit=True, column_widths={'_all': 25})
186
+ ```
187
+
188
+ ### Named Excel Tables
189
+
190
+ Set custom names for Excel tables:
191
+
192
+ ```python
193
+ import xlsxturbo
194
+ import pandas as pd
195
+
196
+ df = pd.DataFrame({'Product': ['A', 'B'], 'Price': [10, 20]})
197
+
198
+ # Name the Excel table
199
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
200
+ table_style="Medium2",
201
+ table_name="ProductPrices"
202
+ )
203
+
204
+ # Invalid characters are auto-sanitized, digits get underscore prefix
205
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
206
+ table_style="Medium2",
207
+ table_name="2024 Sales Data!" # Becomes "_2024_Sales_Data_"
208
+ )
209
+ ```
210
+
211
+ ### Header Styling
212
+
213
+ Apply custom formatting to header cells:
214
+
215
+ ```python
216
+ import xlsxturbo
217
+ import pandas as pd
218
+
219
+ df = pd.DataFrame({'Name': ['Alice', 'Bob'], 'Score': [95, 87]})
220
+
221
+ # Bold headers
222
+ xlsxturbo.df_to_xlsx(df, "bold.xlsx", header_format={'bold': True})
223
+
224
+ # Full styling with colors
225
+ xlsxturbo.df_to_xlsx(df, "styled.xlsx", header_format={
226
+ 'bold': True,
227
+ 'bg_color': '#4F81BD', # Blue background
228
+ 'font_color': 'white' # White text
229
+ })
230
+
231
+ # Available options:
232
+ # - bold (bool): Bold text
233
+ # - italic (bool): Italic text
234
+ # - font_color (str): '#RRGGBB' or named color (white, black, red, blue, etc.)
235
+ # - bg_color (str): Background color
236
+ # - font_size (float): Font size in points
237
+ # - underline (bool): Underlined text
238
+ ```
239
+
240
+ ### Column Formatting
241
+
242
+ Apply formatting to data columns using pattern matching:
243
+
244
+ ```python
245
+ import xlsxturbo
246
+ import pandas as pd
247
+
248
+ df = pd.DataFrame({
249
+ 'product_id': [1, 2, 3],
250
+ 'product_name': ['Widget A', 'Widget B', 'Widget C'],
251
+ 'price_usd': [19.99, 29.99, 39.99],
252
+ 'price_eur': [17.99, 26.99, 35.99],
253
+ 'quantity': [100, 75, 50]
254
+ })
255
+
256
+ # Format columns by pattern
257
+ xlsxturbo.df_to_xlsx(df, "report.xlsx", column_formats={
258
+ 'price_*': {'num_format': '$#,##0.00', 'bg_color': '#E8F5E9'}, # All price columns
259
+ 'quantity': {'bold': True} # Exact match
260
+ })
261
+
262
+ # Wildcard patterns:
263
+ # - 'prefix*' matches columns starting with 'prefix'
264
+ # - '*suffix' matches columns ending with 'suffix'
265
+ # - '*contains*' matches columns containing 'contains'
266
+ # - 'exact' matches column name exactly
267
+
268
+ # Available format options:
269
+ # - bg_color (str): Background color ('#RRGGBB' or named)
270
+ # - font_color (str): Text color
271
+ # - num_format (str): Excel number format ('0.00', '#,##0', '0.00%', etc.)
272
+ # - bold (bool): Bold text
273
+ # - italic (bool): Italic text
274
+ # - underline (bool): Underlined text
275
+ # - border (bool): Add thin border
276
+
277
+ # First matching pattern wins (order preserved)
278
+ xlsxturbo.df_to_xlsx(df, "report.xlsx", column_formats={
279
+ 'price_usd': {'bg_color': '#FFEB3B'}, # Specific: yellow for USD
280
+ 'price_*': {'bg_color': '#E3F2FD'} # General: blue for other prices
281
+ })
282
+ ```
283
+
284
+ ### Multi-Sheet Workbooks
285
+
286
+ ```python
287
+ import xlsxturbo
288
+ import pandas as pd
289
+
290
+ # Write multiple DataFrames to separate sheets
291
+ df1 = pd.DataFrame({'product': ['A', 'B'], 'sales': [100, 200]})
292
+ df2 = pd.DataFrame({'region': ['East', 'West'], 'total': [500, 600]})
293
+
294
+ xlsxturbo.dfs_to_xlsx([
295
+ (df1, "Products"),
296
+ (df2, "Regions")
297
+ ], "report.xlsx")
298
+
299
+ # With styling applied to all sheets
300
+ xlsxturbo.dfs_to_xlsx([
301
+ (df1, "Products"),
302
+ (df2, "Regions")
303
+ ], "styled_report.xlsx", table_style="Medium2", autofit=True, freeze_panes=True)
304
+
305
+ # With column widths applied to all sheets
306
+ xlsxturbo.dfs_to_xlsx([
307
+ (df1, "Products"),
308
+ (df2, "Regions")
309
+ ], "report.xlsx", column_widths={0: 20, 1: 15})
310
+ ```
311
+
312
+ ### Per-Sheet Options
313
+
314
+ Override global settings for individual sheets using a 3-tuple with options dict:
315
+
316
+ ```python
317
+ import xlsxturbo
318
+ import pandas as pd
319
+
320
+ df_data = pd.DataFrame({'Product': ['A', 'B'], 'Price': [10, 20]})
321
+ df_instructions = pd.DataFrame({'Step': [1, 2], 'Action': ['Open file', 'Review data']})
322
+
323
+ # Different settings per sheet:
324
+ # - "Data" sheet: has header, table style, autofit
325
+ # - "Instructions" sheet: no header (raw data), no table style
326
+ xlsxturbo.dfs_to_xlsx([
327
+ (df_data, "Data", {"header": True, "table_style": "Medium2"}),
328
+ (df_instructions, "Instructions", {"header": False, "table_style": None})
329
+ ], "report.xlsx", autofit=True)
330
+
331
+ # Old 2-tuple API still works - uses global defaults
332
+ xlsxturbo.dfs_to_xlsx([
333
+ (df_data, "Sheet1"), # Uses global header=True, table_style=None
334
+ (df_instructions, "Sheet2", {"header": False}) # Override just header
335
+ ], "mixed.xlsx", header=True, autofit=True)
336
+ ```
337
+
338
+ Available per-sheet options:
339
+ - `header` (bool): Include column names as header row
340
+ - `autofit` (bool): Automatically adjust column widths
341
+ - `table_style` (str|None): Excel table style or None to disable
342
+ - `freeze_panes` (bool): Freeze header row
343
+ - `column_widths` (dict): Custom column widths
344
+ - `row_heights` (dict): Custom row heights
345
+ - `table_name` (str): Custom Excel table name
346
+ - `header_format` (dict): Header cell styling
347
+ - `column_formats` (dict): Column formatting with pattern matching
348
+ - `conditional_formats` (dict): Conditional formatting (color scales, data bars, icons)
349
+ - `formula_columns` (dict): Calculated columns with Excel formulas (column name -> formula template)
350
+ - `merged_ranges` (list): List of (range, text) or (range, text, format) tuples to merge cells
351
+ - `hyperlinks` (list): List of (cell, url) or (cell, url, display_text) tuples to add clickable links
352
+ - `comments` (dict): Cell comments/notes (cell_ref -> text or {text, author})
353
+ - `validations` (dict): Data validation rules (column name/pattern -> validation config)
354
+ - `rich_text` (dict): Rich text with multiple formats (cell_ref -> list of segments)
355
+ - `images` (dict): Embedded images (cell_ref -> path or {path, scale_width, scale_height, alt_text})
356
+
357
+ ### Conditional Formatting
358
+
359
+ Apply visual formatting based on cell values:
360
+
361
+ ```python
362
+ import xlsxturbo
363
+ import pandas as pd
364
+
365
+ df = pd.DataFrame({
366
+ 'name': ['Alice', 'Bob', 'Charlie', 'Diana'],
367
+ 'score': [95, 72, 88, 45],
368
+ 'progress': [0.9, 0.5, 0.75, 0.3],
369
+ 'status': [3, 2, 3, 1]
370
+ })
371
+
372
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
373
+ autofit=True,
374
+ conditional_formats={
375
+ # 2-color gradient: red (low) to green (high)
376
+ 'score': {
377
+ 'type': '2_color_scale',
378
+ 'min_color': '#FF6B6B',
379
+ 'max_color': '#51CF66'
380
+ },
381
+ # Data bars: in-cell bar chart
382
+ 'progress': {
383
+ 'type': 'data_bar',
384
+ 'bar_color': '#339AF0',
385
+ 'solid': True # Solid fill instead of gradient
386
+ },
387
+ # Icon set: traffic lights
388
+ 'status': {
389
+ 'type': 'icon_set',
390
+ 'icon_type': '3_traffic_lights'
391
+ }
392
+ }
393
+ )
394
+ ```
395
+
396
+ **Supported conditional format types:**
397
+
398
+ | Type | Options |
399
+ |------|---------|
400
+ | `2_color_scale` | `min_color`, `max_color` |
401
+ | `3_color_scale` | `min_color`, `mid_color`, `max_color` |
402
+ | `data_bar` | `bar_color`, `border_color`, `solid`, `direction` |
403
+ | `icon_set` | `icon_type`, `reverse`, `icons_only` |
404
+
405
+ **Available icon types:**
406
+ - 3 icons: `3_arrows`, `3_arrows_gray`, `3_flags`, `3_traffic_lights`, `3_traffic_lights_rimmed`, `3_signs`, `3_symbols`, `3_symbols_uncircled`
407
+ - 4 icons: `4_arrows`, `4_arrows_gray`, `4_traffic_lights`, `4_rating`
408
+ - 5 icons: `5_arrows`, `5_arrows_gray`, `5_quarters`, `5_rating`
409
+
410
+ Column patterns work with conditional formats:
411
+ ```python
412
+ # Apply data bars to all columns starting with "price_"
413
+ conditional_formats={'price_*': {'type': 'data_bar', 'bar_color': '#9B59B6'}}
414
+ ```
415
+
416
+ ### Formula Columns
417
+
418
+ Add calculated columns to your Excel output. Formulas are written after data columns and use `{row}` as a placeholder for the row number:
419
+
420
+ ```python
421
+ import xlsxturbo
422
+ import pandas as pd
423
+
424
+ df = pd.DataFrame({
425
+ 'price': [100, 200, 150],
426
+ 'quantity': [5, 3, 8],
427
+ 'tax_rate': [0.1, 0.1, 0.2]
428
+ })
429
+
430
+ xlsxturbo.df_to_xlsx(df, "sales.xlsx",
431
+ autofit=True,
432
+ formula_columns={
433
+ 'Subtotal': '=A{row}*B{row}', # price * quantity
434
+ 'Tax': '=D{row}*C{row}', # subtotal * tax_rate
435
+ 'Total': '=D{row}+E{row}' # subtotal + tax
436
+ }
437
+ )
438
+ ```
439
+
440
+ Formula columns appear after data columns (A=price, B=quantity, C=tax_rate, D=Subtotal, E=Tax, F=Total).
441
+
442
+ **Notes:**
443
+ - `{row}` is replaced with the Excel row number (1-based, starting at 2 for data rows when header=True)
444
+ - Formula columns inherit header formatting if specified
445
+ - Column order is preserved (first formula = first new column)
446
+ - Works with both `df_to_xlsx` and `dfs_to_xlsx` (global or per-sheet)
447
+
448
+ ### Merged Cells
449
+
450
+ Merge cell ranges to create headers, titles, or grouped labels:
451
+
452
+ ```python
453
+ import xlsxturbo
454
+ import pandas as pd
455
+
456
+ df = pd.DataFrame({
457
+ 'product': ['Widget A', 'Widget B'],
458
+ 'sales': [1500, 2300],
459
+ 'revenue': [7500, 11500]
460
+ })
461
+
462
+ # Merge cells for a title above the data
463
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
464
+ header=True,
465
+ merged_ranges=[
466
+ # Simple merge with text (auto-centered)
467
+ ('A1:C1', 'Q4 Sales Report'),
468
+ # Merge with custom formatting
469
+ ('A2:C2', 'Regional Data', {
470
+ 'bold': True,
471
+ 'bg_color': '#4F81BD',
472
+ 'font_color': 'white'
473
+ })
474
+ ]
475
+ )
476
+ ```
477
+
478
+ **Merged range format:**
479
+ - Tuple of `(range, text)` or `(range, text, format_dict)`
480
+ - Range uses Excel notation: `'A1:D1'`, `'B3:B10'`, etc.
481
+ - Format options same as `header_format`: bold, italic, font_color, bg_color, font_size, underline
482
+
483
+ **Notes:**
484
+ - Merged cells are applied after data is written, so plan row positions accordingly
485
+ - When using with `header=True`, data starts at row 2 (Excel row 2)
486
+ - Works with both `df_to_xlsx` and `dfs_to_xlsx` (global or per-sheet)
487
+
488
+ ### Hyperlinks
489
+
490
+ Add clickable links to cells:
491
+
492
+ ```python
493
+ import xlsxturbo
494
+ import pandas as pd
495
+
496
+ df = pd.DataFrame({
497
+ 'company': ['Anthropic', 'Google', 'Microsoft'],
498
+ 'product': ['Claude', 'Gemini', 'Copilot'],
499
+ })
500
+
501
+ # Add hyperlinks to a new column (D) after the data columns (A, B, C with header)
502
+ xlsxturbo.df_to_xlsx(df, "companies.xlsx",
503
+ autofit=True,
504
+ hyperlinks=[
505
+ # Header for the links column
506
+ ('C1', 'https://example.com', 'Website'),
507
+ # Links with company names as display text
508
+ ('C2', 'https://anthropic.com', 'anthropic.com'),
509
+ ('C3', 'https://google.com', 'google.com'),
510
+ ('C4', 'https://microsoft.com', 'microsoft.com'),
511
+ ]
512
+ )
513
+ ```
514
+
515
+ **Hyperlink format:**
516
+ - Tuple of `(cell, url)` or `(cell, url, display_text)`
517
+ - Cell uses Excel notation: `'A1'`, `'B5'`, etc.
518
+ - Display text is optional; if omitted, the URL is shown
519
+
520
+ **Notes:**
521
+ - Hyperlinks write to the specified cell position (overwrites existing content)
522
+ - To add a "links column", target cells beyond your DataFrame columns (as shown above)
523
+ - Works with both `df_to_xlsx` and `dfs_to_xlsx` (global or per-sheet)
524
+ - Not available in constant memory mode
525
+
526
+ ### Comments/Notes
527
+
528
+ Add cell annotations (hover to view):
529
+
530
+ ```python
531
+ import xlsxturbo
532
+ import pandas as pd
533
+
534
+ df = pd.DataFrame({
535
+ 'product': ['Widget A', 'Widget B'],
536
+ 'price': [19.99, 29.99]
537
+ })
538
+
539
+ xlsxturbo.df_to_xlsx(df, "report.xlsx",
540
+ comments={
541
+ # Simple text comment
542
+ 'A1': 'This column contains product names',
543
+ # Comment with author
544
+ 'B1': {'text': 'Prices in USD', 'author': 'Finance Team'}
545
+ }
546
+ )
547
+ ```
548
+
549
+ **Comment format:**
550
+ - Simple: `{'A1': 'Note text'}`
551
+ - With author: `{'A1': {'text': 'Note text', 'author': 'Name'}}`
552
+
553
+ **Notes:**
554
+ - Comments appear as small red triangles in the cell corner
555
+ - Hover over the cell to see the comment
556
+ - Works with both `df_to_xlsx` and `dfs_to_xlsx` (global or per-sheet)
557
+ - Not available in constant memory mode
558
+
559
+ ### Data Validation
560
+
561
+ Add dropdowns and input constraints:
562
+
563
+ ```python
564
+ import xlsxturbo
565
+ import pandas as pd
566
+
567
+ df = pd.DataFrame({
568
+ 'status': ['Open', 'Closed'],
569
+ 'score': [85, 92],
570
+ 'price': [19.99, 29.99],
571
+ 'code': ['ABC', 'XYZ']
572
+ })
573
+
574
+ xlsxturbo.df_to_xlsx(df, "validated.xlsx",
575
+ validations={
576
+ # Dropdown list
577
+ 'status': {
578
+ 'type': 'list',
579
+ 'values': ['Open', 'Closed', 'Pending', 'Review']
580
+ },
581
+ # Whole number range (0-100)
582
+ 'score': {
583
+ 'type': 'whole_number',
584
+ 'min': 0,
585
+ 'max': 100,
586
+ 'error_title': 'Invalid Score',
587
+ 'error_message': 'Score must be between 0 and 100'
588
+ },
589
+ # Decimal range
590
+ 'price': {
591
+ 'type': 'decimal',
592
+ 'min': 0.0,
593
+ 'max': 999.99
594
+ },
595
+ # Text length constraint
596
+ 'code': {
597
+ 'type': 'text_length',
598
+ 'min': 3,
599
+ 'max': 10
600
+ }
601
+ }
602
+ )
603
+ ```
604
+
605
+ **Validation types:**
606
+
607
+ | Type | Aliases | Description | Options |
608
+ |------|---------|-------------|---------|
609
+ | `list` | - | Dropdown menu | `values` (list of strings, max 255 chars total) |
610
+ | `whole_number` | `whole`, `integer` | Integer range | `min`, `max` |
611
+ | `decimal` | `number` | Decimal range | `min`, `max` |
612
+ | `text_length` | `textlength`, `length` | Character count | `min`, `max` |
613
+
614
+ **Optional message options:**
615
+ - `input_title`, `input_message`: Prompt shown when cell is selected
616
+ - `error_title`, `error_message`: Message shown when invalid data is entered
617
+
618
+ **Notes:**
619
+ - Validations apply to the data rows of the specified column
620
+ - Column patterns work: `'score_*': {...}` matches all columns starting with `score_`
621
+ - If only `min` or only `max` is specified, the other defaults to the type's extreme value
622
+ - List validation values are limited to 255 total characters (Excel limitation)
623
+ - Works with both `df_to_xlsx` and `dfs_to_xlsx` (global or per-sheet)
624
+ - Not available in constant memory mode
625
+
626
+ ### Rich Text
627
+
628
+ Multiple formats within a single cell:
629
+
630
+ ```python
631
+ import xlsxturbo
632
+ import pandas as pd
633
+
634
+ df = pd.DataFrame({'A': [1, 2, 3]})
635
+
636
+ xlsxturbo.df_to_xlsx(df, "rich.xlsx",
637
+ rich_text={
638
+ 'D1': [
639
+ ('Important: ', {'bold': True, 'font_color': 'red'}),
640
+ 'Please review ',
641
+ ('all', {'italic': True}),
642
+ ' values'
643
+ ],
644
+ 'D2': [
645
+ ('Status: ', {'bold': True}),
646
+ ('OK', {'font_color': 'green', 'bold': True})
647
+ ]
648
+ }
649
+ )
650
+ ```
651
+
652
+ **Segment format:**
653
+ - Formatted: `('text', {'bold': True, 'font_color': 'blue'})`
654
+ - Plain: `'plain text'` (no formatting)
655
+
656
+ **Available format options:**
657
+ - `bold` (bool)
658
+ - `italic` (bool)
659
+ - `font_color` (str): '#RRGGBB' or named color
660
+ - `bg_color` (str): Background color
661
+ - `font_size` (float)
662
+ - `underline` (bool)
663
+
664
+ **Notes:**
665
+ - Rich text writes to the specified cell position (overwrites existing content)
666
+ - Works with both `df_to_xlsx` and `dfs_to_xlsx` (global or per-sheet)
667
+ - Not available in constant memory mode
668
+
669
+ ### Images
670
+
671
+ Embed images in cells:
672
+
673
+ ```python
674
+ import xlsxturbo
675
+ import pandas as pd
676
+
677
+ df = pd.DataFrame({'Product': ['Widget A', 'Widget B'], 'Price': [19.99, 29.99]})
678
+
679
+ xlsxturbo.df_to_xlsx(df, "catalog.xlsx",
680
+ autofit=True,
681
+ images={
682
+ # Simple path
683
+ 'C2': 'images/widget_a.png',
684
+ # With options
685
+ 'C3': {
686
+ 'path': 'images/widget_b.png',
687
+ 'scale_width': 0.5,
688
+ 'scale_height': 0.5,
689
+ 'alt_text': 'Widget B photo'
690
+ }
691
+ }
692
+ )
693
+ ```
694
+
695
+ **Image format:**
696
+ - Simple: `{'C2': 'path/to/image.png'}`
697
+ - With options: `{'C2': {'path': '...', 'scale_width': 0.5, ...}}`
698
+
699
+ **Available options:**
700
+ - `path` (str, required): Path to image file
701
+ - `scale_width` (float): Width scale factor (1.0 = original)
702
+ - `scale_height` (float): Height scale factor (1.0 = original)
703
+ - `alt_text` (str): Alternative text for accessibility
704
+
705
+ **Supported formats:** PNG, JPEG, GIF, BMP
706
+
707
+ **Notes:**
708
+ - Images are positioned at the specified cell (overlays any existing content)
709
+ - Image file must exist; non-existent files will raise an error
710
+ - Works with both `df_to_xlsx` and `dfs_to_xlsx` (global or per-sheet)
711
+ - Not available in constant memory mode
712
+
713
+ ### Constant Memory Mode (Large Files)
714
+
715
+ For very large files (millions of rows), use `constant_memory=True` to minimize RAM usage:
716
+
717
+ ```python
718
+ import xlsxturbo
719
+ import polars as pl
720
+
721
+ # Generate a large DataFrame
722
+ large_df = pl.DataFrame({
723
+ 'id': range(1_000_000),
724
+ 'value': [i * 1.5 for i in range(1_000_000)]
725
+ })
726
+
727
+ # Use constant_memory mode for large files
728
+ xlsxturbo.df_to_xlsx(large_df, "big_file.xlsx", constant_memory=True)
729
+
730
+ # Also works with dfs_to_xlsx
731
+ xlsxturbo.dfs_to_xlsx([
732
+ (large_df, "Data")
733
+ ], "multi_sheet.xlsx", constant_memory=True)
734
+ ```
735
+
736
+ **Note:** Constant memory mode disables some features that require random access:
737
+ - `table_style` (Excel tables)
738
+ - `freeze_panes`
739
+ - `row_heights`
740
+ - `conditional_formats`
741
+ - `merged_ranges`
742
+ - `hyperlinks`
743
+ - `comments`
744
+ - `validations`
745
+ - `rich_text`
746
+ - `images`
747
+ - `autofit`
748
+ - `conditional_formats`
749
+ - `formula_columns`
750
+ - `merged_ranges`
751
+ - `hyperlinks`
752
+
753
+ Column widths still work in constant memory mode.
754
+
755
+ ### CSV Conversion
756
+
757
+ ```python
758
+ import xlsxturbo
759
+
760
+ # Convert CSV to XLSX with automatic type detection
761
+ rows, cols = xlsxturbo.csv_to_xlsx("input.csv", "output.xlsx")
762
+ print(f"Converted {rows} rows and {cols} columns")
763
+
764
+ # Custom sheet name
765
+ xlsxturbo.csv_to_xlsx("data.csv", "report.xlsx", sheet_name="Sales Data")
766
+
767
+ # For large files (100K+ rows), use parallel processing
768
+ xlsxturbo.csv_to_xlsx("big_data.csv", "output.xlsx", parallel=True)
769
+
770
+ # Handle ambiguous dates (01-02-2024: is it Jan 2 or Feb 1?)
771
+ xlsxturbo.csv_to_xlsx("us_data.csv", "output.xlsx", date_order="us") # January 2
772
+ xlsxturbo.csv_to_xlsx("eu_data.csv", "output.xlsx", date_order="eu") # February 1
773
+
774
+ # date_order options:
775
+ # - "auto" (default): ISO first, then European (DMY), then US (MDY)
776
+ # - "mdy" or "us": US format (MM-DD-YYYY)
777
+ # - "dmy" or "eu": European format (DD-MM-YYYY)
778
+ ```
779
+
780
+ ## CLI Usage
781
+
782
+ ```bash
783
+ xlsxturbo input.csv output.xlsx [OPTIONS]
784
+ ```
785
+
786
+ ### Options
787
+
788
+ - `-s, --sheet-name <NAME>`: Name of the Excel sheet (default: "Sheet1")
789
+ - `-d, --date-order <ORDER>`: Date parsing order for ambiguous dates (default: "auto")
790
+ - `auto`: ISO first, then European, then US
791
+ - `mdy` or `us`: US format (01-02-2024 = January 2)
792
+ - `dmy` or `eu`: European format (01-02-2024 = February 1)
793
+ - `-v, --verbose`: Show progress information
794
+
795
+ ### Examples
796
+
797
+ ```bash
798
+ # Basic conversion
799
+ xlsxturbo sales.csv report.xlsx
800
+
801
+ # With US date format
802
+ xlsxturbo sales.csv report.xlsx --date-order us
803
+
804
+ # With European date format and verbose output
805
+ xlsxturbo sales.csv report.xlsx -d eu -v --sheet-name "Q4 Sales"
806
+ ```
807
+
808
+ ## Performance
809
+
810
+ *Reference benchmark on 100,000 rows x 50 columns with mixed data types. Your results will vary by system - run the benchmark yourself (see [Benchmarking](#benchmarking)).*
811
+
812
+ | Library | Time (s) | Rows/sec | vs xlsxturbo |
813
+ |---------|----------|----------|--------------|
814
+ | **xlsxturbo** | **6.65** | **15,033** | **1.0x** |
815
+ | polars | 25.07 | 3,988 | 3.8x |
816
+ | pandas + xlsxwriter | 35.60 | 2,809 | 5.4x |
817
+ | pandas + openpyxl | 38.85 | 2,574 | 5.8x |
818
+
819
+ *Test system: Windows 11, Python 3.14, AMD Ryzen 9 (32 threads)*
820
+
821
+ ## Type Detection Examples
822
+
823
+ | CSV Value | Excel Type | Notes |
824
+ |-----------|------------|-------|
825
+ | `123` | Number | Integer |
826
+ | `3.14159` | Number | Float |
827
+ | `true` / `FALSE` | Boolean | Case insensitive |
828
+ | `2024-01-15` | Date | Formatted as date |
829
+ | `2024-01-15T10:30:00` | DateTime | ISO 8601 format |
830
+ | `NaN` | Empty | Graceful handling |
831
+ | `hello world` | Text | Default |
832
+
833
+ Supported date formats: `YYYY-MM-DD`, `YYYY/MM/DD`, `DD-MM-YYYY`, `DD/MM/YYYY`, `MM-DD-YYYY`, `MM/DD/YYYY`
834
+
835
+ ## Building from Source
836
+
837
+ Requires Rust toolchain and maturin:
838
+
839
+ ```bash
840
+ # Install maturin
841
+ pip install maturin
842
+
843
+ # Development build
844
+ maturin develop
845
+
846
+ # Release build (optimized)
847
+ maturin develop --release
848
+
849
+ # Build wheel for distribution
850
+ maturin build --release
851
+ ```
852
+
853
+ ## Benchmarking
854
+
855
+ Run the included benchmark scripts:
856
+
857
+ ```bash
858
+ # Compare xlsxturbo vs other libraries (100K rows default)
859
+ python benchmarks/benchmark.py
860
+
861
+ # Full benchmark: small, medium, large datasets
862
+ python benchmarks/benchmark.py --full
863
+
864
+ # Custom size
865
+ python benchmarks/benchmark.py --rows 500000 --cols 100
866
+
867
+ # Output formats for CI/documentation
868
+ python benchmarks/benchmark.py --markdown
869
+ python benchmarks/benchmark.py --json
870
+
871
+ # Test parallel vs single-threaded CSV conversion
872
+ python benchmarks/benchmark_parallel.py
873
+ ```
874
+
875
+ ## License
876
+
877
+ MIT
878
+
@@ -0,0 +1,7 @@
1
+ xlsxturbo/__init__.py,sha256=jekxkYh-HO_u7AQd4aV3MW7yZJlMx5cXryS0WzwasDs,200
2
+ xlsxturbo/__init__.pyi,sha256=LwVxEb66h5BI81gzAYz5du0O1I2E327dNcBcc5baQUw,13662
3
+ xlsxturbo/xlsxturbo.abi3.so,sha256=YX_21-JERbyGql94T42anjCe6hjDZfXJVxfcBndD9_Q,1930816
4
+ xlsxturbo-0.10.1.dist-info/METADATA,sha256=EN7XLwDMGh3iLNuVxzcUlP0Dpi4epilYlbp2HvbsMck,26186
5
+ xlsxturbo-0.10.1.dist-info/WHEEL,sha256=82nIVBZDB2dcFlYZh5-bKZ63xGZXWMnioaoSK06flpU,103
6
+ xlsxturbo-0.10.1.dist-info/licenses/LICENSE,sha256=dUhuoK-TCRQMpuLEAdfme-qPSJI0TlcH9jlNxeg9_EQ,1056
7
+ xlsxturbo-0.10.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: maturin (1.11.5)
3
+ Root-Is-Purelib: false
4
+ Tag: cp38-abi3-macosx_11_0_arm64
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.