-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_encoding.py
More file actions
286 lines (219 loc) · 6.66 KB
/
Copy pathexample_encoding.py
File metadata and controls
286 lines (219 loc) · 6.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
import marimo
__generated_with = "0.19.2"
app = marimo.App(width="medium")
with app.setup:
import marimo as mo
import pandas as pd
import psycopg
from table_functions import add_files_to_metadata_table, update_table
@app.cell
def _():
mo.md("""
# Working with Different Character Encodings
This notebook demonstrates how to ingest files with non-UTF-8 encodings,
specifically CP-1252 (Windows-1252), which is common in files from Excel
or legacy Windows systems.
## Common Encodings
- **utf-8** (default): Universal, supports all languages
- **cp1252** (Windows-1252): Common for Excel exports, Western European languages
- **latin1** (ISO-8859-1): Western European languages
- **utf-8-sig**: UTF-8 with BOM (Byte Order Mark)
## The Problem
Files with special characters like:
- Café, Münchën, François
- São Paulo, México
- ñ, é, ü, ç, ã, ó
Will fail to ingest if you use the wrong encoding!
""")
return
@app.cell
def _():
# Connection string for all database operations
conninfo = "postgresql://tanner@localhost:5432/postgres"
# Create a connection for mo.sql() queries
conn = psycopg.connect(conninfo, autocommit=False)
# Create schema
with conn.cursor() as cur:
cur.execute("CREATE SCHEMA IF NOT EXISTS test_encoding")
conn.commit()
# Setup paths
base_dir = mo.notebook_dir().parent
source_dir = base_dir / "data" / "raw" / "encoding_test"
# Create directories
source_dir.mkdir(parents=True, exist_ok=True)
return conn, conninfo, source_dir
@app.cell
def _(mo, source_dir):
mo.md(f"""
## Step 1: Create Sample CP-1252 File
Let's create a test file with special characters in CP-1252 encoding.
This simulates receiving a file exported from Excel.
**File location:** `{source_dir}/restaurants.csv`
""")
return
@app.cell
def _(source_dir):
# Create sample CP-1252 encoded file
content = """Name,City,Description,Price
Café Münchën,São Paulo,Delicious café with ñoño,12.50
Restaurant François,Montréal,Best crêpes in town,15.75
José's Taquería,México,Señor José's specialty,8.99
"""
file_path = source_dir / "restaurants.csv"
with open(file_path, "w", encoding="cp1252") as f:
f.write(content)
print(f"✓ Created CP-1252 encoded file: {file_path}")
return
@app.cell
def _(mo):
mo.md("""
## Step 2: Add to Metadata with Encoding Parameter
**Key parameter:** `encoding="cp1252"`
Without this, you'll get errors like:
```
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9
```
""")
return
@app.cell
def _(add_files_to_metadata_table, conninfo, source_dir):
# Add files to metadata with CP-1252 encoding
metadata_df = add_files_to_metadata_table(
conninfo=conninfo,
schema="test_encoding",
source_dir=str(source_dir),
filetype="csv",
has_header=True,
encoding="cp1252", # ← Specify the encoding!
resume=True,
)
return (metadata_df,)
@app.cell
def _(metadata_df, mo):
mo.ui.table(
metadata_df[["source_path", "header", "row_count", "metadata_ingest_status"]]
)
return
@app.cell
def _(mo):
mo.md("""
## Step 3: Infer Schema with Encoding
Use the CLI with `--encoding` parameter:
```bash
python table_functions.py data/landing/encoding_test/restaurants.csv --encoding cp1252 --pretty
```
""")
return
@app.cell
def _(mo):
mo.md("""
## Step 4: Ingest Data with Encoding Parameter
`update_table()` now supports the encoding parameter directly!
No need for `custom_read_fn` unless you need custom logic.
""")
return
@app.cell
def _(conninfo, source_dir, update_table):
# Define column mapping from schema inference
column_mapping = {
"name": (["Name"], "string"),
"city": (["City"], "string"),
"description": (["Description"], "string"),
"price": (["Price"], "float64"),
}
# Ingest with encoding parameter
ingest_df = update_table(
conninfo=conninfo,
schema="test_encoding",
output_table="restaurants",
filetype="csv",
source_dir=str(source_dir),
column_mapping=column_mapping,
encoding="cp1252", # ← Simply specify encoding!
resume=True,
)
return (ingest_df,)
@app.cell
def _(ingest_df, mo):
mo.ui.table(ingest_df[["source_path", "status", "ingest_runtime"]])
return
@app.cell
def _(mo):
mo.md("""
## Step 5: Verify Special Characters
Check that special characters were preserved correctly:
""")
return
@app.cell
def _(conn, mo):
result_df = mo.sql(
f"""
SELECT "Name", "City", "Description", "Price"
FROM test_encoding.restaurants
ORDER BY "Price"
""",
engine=conn,
)
return (result_df,)
@app.cell
def _(mo, result_df):
mo.md(f"""
### Results
✓ All special characters preserved correctly!
{mo.ui.table(result_df)}
Characters preserved: **é, ü, ñ, ã, ç, ó**
""")
return
@app.cell
def _(mo):
mo.md("""
## Summary: Encoding Best Practices
### 1. For `add_files_to_metadata_table()`
```python
add_files_to_metadata_table(
conninfo="postgresql://user:pass@host/db",
schema="raw",
source_dir="data/raw/",
filetype="csv",
encoding="cp1252", # Specify encoding
)
```
### 2. For `update_table()` - Direct encoding parameter
```python
update_table(
conninfo="postgresql://user:pass@host/db",
schema="raw",
output_table="my_table",
filetype="csv",
source_dir="data/raw/",
column_mapping=column_mapping,
encoding="cp1252", # ← Simply specify encoding!
)
```
**Alternative:** For custom logic, use `custom_read_fn`:
```python
def custom_reader(full_path):
return pd.read_csv(full_path, encoding='cp1252', dtype={...})
update_table(..., custom_read_fn=custom_reader)
```
### 3. For Schema Inference
```bash
python table_functions.py file.csv --encoding cp1252 --pretty
```
### Common Encodings
- `utf-8` - Universal (default)
- `cp1252` - Windows-1252, Excel exports
- `latin1` - ISO-8859-1, Western European
- `utf-8-sig` - UTF-8 with BOM
### Encoding Detection
If unsure about the encoding, use chardet:
```python
import chardet
with open('file.csv', 'rb') as f:
result = chardet.detect(f.read())
print(result['encoding']) # e.g., 'Windows-1252'
```
""")
return
if __name__ == "__main__":
app.run()