Repository: jmcnamara/XlsxWriter

Issue:
Bug: `TypeError` raised when autofitting an empty worksheet
### Current behavior

If you have an empty `Worksheet` and try to autofit, an unexpected `TypeError` is raised.

### Expected behavior

Should not raise an exception if there happens to be nothing to autofit.

### Sample code to reproduce

```python
from xlsxwriter import Workbook

with Workbook('hello.xlsx') as wb:
    ws = wb.add_worksheet()
    ws.autofit()

# TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
```


### Environment

```markdown
- XlsxWriter version: 3.0.8
- Python version: 3.11
```


### Any other information

_No response_

### OpenOffice and LibreOffice users

- [ ] I have tested the output file with Excel.

Discussion:
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=jmcnamara_XlsxWriter&pullRequest=956)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=jmcnamara_XlsxWriter&pullRequest=956&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=jmcnamara_XlsxWriter&pullRequest=956) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=jmcnamara_XlsxWriter&pullRequest=956&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=jmcnamara_XlsxWriter&pullRequest=956&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/xlsxwriter/worksheet.py b/xlsxwriter/worksheet.py
index 7e14ff8b..c935f130 100644
--- a/xlsxwriter/worksheet.py
+++ b/xlsxwriter/worksheet.py
@@ -1835,6 +1835,10 @@ class Worksheet(xmlwriter.XMLwriter):
             warn("Autofit is not supported in constant_memory mode.")
             return
 
+        # No data written to the target sheet; nothing to autofit
+        if self.dim_rowmax is None:
+            return
+
         # Store the max pixel width for each column.
         col_width_max = {}
 


Test patch:
diff --git a/xlsxwriter/test/comparison/test_autofit01.py b/xlsxwriter/test/comparison/test_autofit01.py
index db83a060..855ae889 100644
--- a/xlsxwriter/test/comparison/test_autofit01.py
+++ b/xlsxwriter/test/comparison/test_autofit01.py
@@ -24,9 +24,12 @@ class TestCompareXLSXFiles(ExcelComparisonTest):
         """Test the creation of a simple XlsxWriter file."""
 
         workbook = Workbook(self.got_filename)
-
         worksheet = workbook.add_worksheet()
 
+        # Before writing data, nothing to autofit (should not raise)
+        worksheet.autofit()
+
+        # Write something that can be autofit
         worksheet.write_string(0, 0, "A")
 
         # Check for handling default/None width.