atio


Nameatio JSON
Version 1.0.0 PyPI version JSON
download
home_pageNone
SummarySafe atomic file writer for Pandas, Polars, NumPy, and other data objects
upload_time2025-08-02 08:57:23
maintainerNone
docs_urlNone
authorNone
requires_python>=3.7
licenseApache-2.0
keywords atomic file writer pandas polars numpy data
VCS
bugtrack_url
requirements pandas pyarrow polars pytest build twine
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Atio ๐Ÿ›ก๏ธ

์•ˆ์ „ํ•˜๊ณ  **์›์ž์ ์ธ ํŒŒ์ผ ์“ฐ๊ธฐ**๋ฅผ ์ง€์›ํ•˜๋Š” ๊ฒฝ๋Ÿ‰ Python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ž…๋‹ˆ๋‹ค.  
Pandas, Polars, NumPy ๋“ฑ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด ์ €์žฅ ์‹œ **ํŒŒ์ผ ์†์ƒ ์—†์ด**, **ํŠธ๋žœ์žญ์…˜์ฒ˜๋Ÿผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ**ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---

## ๐ŸŒŸ ์ฃผ์š” ๊ธฐ๋Šฅ

- โœ… ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์Šคํ…Œ์ด์ง• ํ›„ **์›์ž์  ํŒŒ์ผ ๊ต์ฒด**  
- ๐Ÿ“ฆ Pandas, Polars, NumPy ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด ์ง€์›  
- ๐Ÿ“ `_SUCCESS` ํ”Œ๋ž˜๊ทธ ํŒŒ์ผ ์ƒ์„ฑ โ€” ์ €์žฅ ์™„๋ฃŒ ์—ฌ๋ถ€ ํ‘œ์‹œ  
- ๐Ÿ›  ์‹คํŒจ ์‹œ **์›๋ณธ ํŒŒ์ผ ๋ณด์กด**, ์ž„์‹œ ํŒŒ์ผ ์ž๋™ ์ •๋ฆฌ  
- ๐Ÿงฉ ํ”Œ๋Ÿฌ๊ทธ์ธ ์•„ํ‚คํ…์ฒ˜๋กœ **ํ™•์žฅ์„ฑ ์ข‹์Œ**
- ๐Ÿ” **์„ฑ๋Šฅ ์ง„๋‹จ ๋กœ๊น…** โ€” ๊ฐ ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ ์‹œ๊ฐ„ ์ธก์ • ๋ฐ ๋ณ‘๋ชฉ์  ๋ถ„์„

---

## ๐Ÿ” ์„ฑ๋Šฅ ์ง„๋‹จ ๋กœ๊น… (NEW!)

Atio๋Š” ์ด์ œ **์„ฑ๋Šฅ ์ง„๋‹จ ๋กœ๊น…** ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. `verbose=True` ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ ์‹œ๊ฐ„์„ ์ธก์ •ํ•˜์—ฌ ๋ณ‘๋ชฉ์ ์„ ์ •ํ™•ํžˆ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

### ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ• (๊ฐ„๋‹จํ•œ ์ •๋ณด๋งŒ):
```python
import atio as aw
import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3]})

# ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ• - ๊ฐ„๋‹จํ•œ ์„ฑ๊ณต/์‹คํŒจ ์ •๋ณด๋งŒ
aw.write(df, "output.parquet", format="parquet")
```

**์ถœ๋ ฅ ์˜ˆ์‹œ:**
```
[INFO] ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ: /tmp/tmp_xxx
[INFO] ์ž„์‹œ ํŒŒ์ผ ๊ฒฝ๋กœ: /tmp/tmp_xxx/output.parquet
[INFO] ์‚ฌ์šฉํ•  writer: to_parquet (format: parquet)
[INFO] ๋ฐ์ดํ„ฐ ์ž„์‹œ ํŒŒ์ผ์— ์ €์žฅ ์™„๋ฃŒ: /tmp/tmp_xxx/output.parquet
[INFO] ์›์ž์  ๊ต์ฒด ์™„๋ฃŒ: /tmp/tmp_xxx/output.parquet -> output.parquet
[INFO] _SUCCESS ํ”Œ๋ž˜๊ทธ ํŒŒ์ผ ์ƒ์„ฑ: output.parquet._SUCCESS
[INFO] Atomic write completed successfully (took 0.2359s)
```

### ์ƒ์„ธ ์ง„๋‹จ ๋ชจ๋“œ (verbose=True):
```python
# ์ƒ์„ธํ•œ ์„ฑ๋Šฅ ์ง„๋‹จ ์ •๋ณด ์ถœ๋ ฅ
aw.write(df, "output.parquet", format="parquet", verbose=True)
```

**์ถœ๋ ฅ ์˜ˆ์‹œ:**
```
[INFO] ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ: /tmp/tmp_xxx
[INFO] ์ž„์‹œ ํŒŒ์ผ ๊ฒฝ๋กœ: /tmp/tmp_xxx/output.parquet
[INFO] ์‚ฌ์šฉํ•  writer: to_parquet (format: parquet)
[INFO] ๋ฐ์ดํ„ฐ ์ž„์‹œ ํŒŒ์ผ์— ์ €์žฅ ์™„๋ฃŒ: /tmp/tmp_xxx/output.parquet
[INFO] ์›์ž์  ๊ต์ฒด ์™„๋ฃŒ: /tmp/tmp_xxx/output.parquet -> output.parquet
[INFO] _SUCCESS ํ”Œ๋ž˜๊ทธ ํŒŒ์ผ ์ƒ์„ฑ: output.parquet._SUCCESS
[DEBUG] Atomic write step timings (SUCCESS): setup=0.0012s, write_call=0.2345s, replace=0.0001s, success_flag=0.0001s, total=0.2359s
```

### ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ (๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•):
```
[INFO] ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ: /tmp/tmp_xxx
[INFO] ์ž„์‹œ ํŒŒ์ผ ๊ฒฝ๋กœ: /tmp/tmp_xxx/output.parquet
[INFO] ์‚ฌ์šฉํ•  writer: to_parquet (format: parquet)
[ERROR] ์ž„์‹œ ํŒŒ์ผ ์ €์žฅ ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: [Errno 28] No space left on device
[INFO] Atomic write failed during write stage (took 0.1246s, error: OSError)
```

### ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œ (verbose=True):
```
[INFO] ์ž„์‹œ ๋””๋ ‰ํ† ๋ฆฌ ์ƒ์„ฑ: /tmp/tmp_xxx
[INFO] ์ž„์‹œ ํŒŒ์ผ ๊ฒฝ๋กœ: /tmp/tmp_xxx/output.parquet
[INFO] ์‚ฌ์šฉํ•  writer: to_parquet (format: parquet)
[ERROR] ์ž„์‹œ ํŒŒ์ผ ์ €์žฅ ์ค‘ ์˜ˆ์™ธ ๋ฐœ์ƒ: [Errno 28] No space left on device
[DEBUG] Atomic write step timings (ERROR during write): setup=0.0012s, write_call=0.1234s (์‹คํŒจ), replace=N/A, success_flag=N/A, total=0.1246s, error_type=OSError
```

**์ธก์ •๋˜๋Š” ๋‹จ๊ณ„:**
- `setup`: ์ž„์‹œ ํด๋” ์ƒ์„ฑ ๋ฐ ์ดˆ๊ธฐ ์„ค์ •
- `write_call`: ์‹ค์ œ ๋ฐ์ดํ„ฐ ์“ฐ๊ธฐ ํ•จ์ˆ˜ ํ˜ธ์ถœ (๋Œ€๋ถ€๋ถ„์˜ ์‹œ๊ฐ„ ์†Œ์š”)
- `replace`: ์›์ž์  ํŒŒ์ผ ๊ต์ฒด
- `success_flag`: _SUCCESS ํ”Œ๋ž˜๊ทธ ํŒŒ์ผ ์ƒ์„ฑ
- `total`: ์ „์ฒด ์ž‘์—… ์‹œ๊ฐ„

**์ง€์›ํ•˜๋Š” ์˜ค๋ฅ˜ ์ƒํ™ฉ:**
- โœ… **KeyboardInterrupt**: ์ธํ„ฐ๋ŸฝํŠธ ๋ฐœ์ƒ ์‹œ์ ๊ณผ ์†Œ์š” ์‹œ๊ฐ„ ํ‘œ์‹œ
- โœ… **๊ถŒํ•œ ์˜ค๋ฅ˜**: ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ถŒํ•œ ๋ฌธ์ œ ์ง„๋‹จ
- โœ… **๋””์Šคํฌ ๊ณต๊ฐ„ ๋ถ€์กฑ**: ์ €์žฅ ๊ณต๊ฐ„ ๋ถ€์กฑ ์ƒํ™ฉ ์ง„๋‹จ
- โœ… **๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ**: ๋ฉ”๋ชจ๋ฆฌ ์••๋ฐ• ์ƒํ™ฉ ์ง„๋‹จ
- โœ… **๋„คํŠธ์›Œํฌ ์˜ค๋ฅ˜**: ๋„คํŠธ์›Œํฌ ๋“œ๋ผ์ด๋ธŒ ์ ‘๊ทผ ๋ฌธ์ œ ์ง„๋‹จ
- โœ… **์ง€์›ํ•˜์ง€ ์•Š๋Š” ํ˜•์‹**: ์ž˜๋ชป๋œ ํŒŒ์ผ ํ˜•์‹ ์ง€์ • ์‹œ ์ง„๋‹จ
- โœ… **๋™์‹œ ์ ‘๊ทผ ์˜ค๋ฅ˜**: ๋ฉ€ํ‹ฐ์Šค๋ ˆ๋”ฉ ํ™˜๊ฒฝ์—์„œ์˜ ์ถฉ๋Œ ์ง„๋‹จ

**์žฅ์ :**
- ๐ŸŽฏ **์ •ํ™•ํ•œ ๋ณ‘๋ชฉ์  ํŒŒ์•…**: Atio ์˜ค๋ฒ„ํ—ค๋“œ vs ์‹ค์ œ ์“ฐ๊ธฐ ์ž‘์—… ์‹œ๊ฐ„ ๊ตฌ๋ถ„
- ๐Ÿ”ง **์„ฑ๋Šฅ ์ตœ์ ํ™” ๊ฐ€์ด๋“œ**: ์–ด๋А ๋‹จ๊ณ„์—์„œ ์‹œ๊ฐ„์ด ๋งŽ์ด ์†Œ์š”๋˜๋Š”์ง€ ๋ช…ํ™•ํžˆ ํ‘œ์‹œ
- ๐Ÿ› **๋””๋ฒ„๊น… ์‹œ๊ฐ„ ๋‹จ์ถ•**: ๋ฌธ์ œ์˜ ์›์ธ์„ ๋น ๋ฅด๊ฒŒ ํŒŒ์•… ๊ฐ€๋Šฅ
- ๐Ÿ“Š **์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง**: ๋Œ€์šฉ๋Ÿ‰ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ์‹œ ์„ฑ๋Šฅ ์ถ”์ 
- ๐Ÿšจ **์˜ค๋ฅ˜ ์ง„๋‹จ**: ์‹คํŒจ ์ƒํ™ฉ์—์„œ๋„ ์ •ํ™•ํ•œ ์›์ธ๊ณผ ๋ฐœ์ƒ ์‹œ์  ํŒŒ์•…

---

## ๐Ÿง  ์™œ ์ด ๋„๊ตฌ๊ฐ€ ์ •๋ง ์ค‘์š”ํ•œ๊ฐ€์š”?

NumPy๋‚˜ Pandas๋Š” ๋ฐ์ดํ„ฐ ๋ถ„์„์—์„œ๋Š” ์ตœ์ ์ด์ง€๋งŒ, **ํŒŒ์ผ๋กœ ์ €์žฅํ•  ๋•Œ๋Š” ์•„๋ž˜์™€ ๊ฐ™์€ ์œ„ํ—˜**์ด ์žˆ์Šต๋‹ˆ๋‹ค:

1. **ํŒŒ์ผ ์ผ๋ถ€๋งŒ ์ €์žฅ๋˜์–ด ๊นจ์งˆ ์ˆ˜ ์žˆ์Œ** โ€” ๊ฐ•์ œ ์ข…๋ฃŒ๋‚˜ ์˜ค๋ฅ˜ ์‹œ
2. **๋™์‹œ ์“ฐ๊ธฐ ์ถฉ๋Œ** โ€” ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค ํ™˜๊ฒฝ์—์„œ ํŒŒ์ผ์ด ์—‰ํ‚ฌ ์ˆ˜ ์žˆ์Œ
3. **ํ”Œ๋žซํผ ๊ฐ„ ๋™์ž‘ ์ฐจ์ด** โ€” Windows์™€ Linux/macOS์—์„œ ํŒŒ์ผ ์‹œ์Šคํ…œ ๋™์ž‘์ด ๋‹ค๋ฆ„

AtomicWriter๋Š” ์ž„์‹œ ํŒŒ์ผ์— ์“ฐ๊ณ  **๋‹จ์ผ `rename()`/`replace()` ์ž‘์—…์œผ๋กœ ๊ต์ฒด**ํ•ฉ๋‹ˆ๋‹ค.  
์ด ๋ฐฉ์‹์€ **โ€œ์™„์ „ํžˆ ์ €์žฅ๋˜๊ฑฐ๋‚˜ ์ „ํ˜€ ์ €์žฅ๋˜์ง€ ์•Š๋Š”โ€** ์›์ž์„ฑ(atomicity)์„ ๋ณด์žฅํ•˜๋ฉฐ,  
- POSIX: `os.replace` (atomic), `fsync`  
- Windows: `MoveFileEx`, `Commit`  
๋ฅผ ํ™œ์šฉํ•˜์—ฌ ํŒŒ์ผ์ด **ํ•ญ์ƒ ์ผ๊ด€๋œ ์ƒํƒœ**๋ฅผ ์œ ์ง€ํ•˜๋„๋ก ํ•ฉ๋‹ˆ๋‹ค :contentReference[oaicite:1]{index=1}.

---

## โš™๏ธ ์„ค์น˜

```bash
pip install atomicwriter

## ๐Ÿ› ๏ธ ์‚ฌ์šฉ ์˜ˆ์ œ

```python
import atomicwriter as aw
import pandas as pd

df = pd.DataFrame({"a": [1, 2, 3]})

# ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•
aw.write(df, "output.parquet", format="parquet")
# โ”‚โ†’ ์ž„์‹œ ํŒŒ์ผ ์ž‘์„ฑ โ†’ ์›์ž์  ๊ต์ฒด โ†’ _SUCCESS ์ƒ์„ฑ
# โ”‚โ†’ ์‹คํŒจ ์‹œ ์›๋ณธ ๋ณด์กด, ์ž„์‹œ ํŒŒ์ผ ์ž๋™ ์ •๋ฆฌ

# ์ƒ์„ธ ์„ฑ๋Šฅ ์ง„๋‹จ ๋กœ๊น… ํ™œ์„ฑํ™”
aw.write(df, "output_verbose.parquet", format="parquet", verbose=True)
# โ”‚โ†’ ๊ฐ ๋‹จ๊ณ„๋ณ„ ์‹คํ–‰ ์‹œ๊ฐ„ ์ธก์ • ๋ฐ ๋กœ๊ทธ ์ถœ๋ ฅ

# ์ง„ํ–‰๋„ ํ‘œ์‹œ์™€ ํ•จ๊ป˜ ์‚ฌ์šฉ
aw.write(df, "output_progress.parquet", format="parquet", show_progress=True)
# โ”‚โ†’ ์‹ค์‹œ๊ฐ„ ์ง„ํ–‰๋„ ํ‘œ์‹œ

# ๋ชจ๋“  ์˜ต์…˜ ์กฐํ•ฉ
aw.write(df, "output_full.parquet", format="parquet", 
         verbose=True, show_progress=True)
# โ”‚โ†’ ์„ฑ๋Šฅ ์ง„๋‹จ + ์ง„ํ–‰๋„ ํ‘œ์‹œ
```

## ๐Ÿ’ก ๋น…๋ฐ์ดํ„ฐ ์›Œํฌํ”Œ๋กœ์šฐ์—์„œ ํ™œ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค

| ์‹œ๋‚˜๋ฆฌ์˜ค               | ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•                   | ์žฅ์                     |
|------------------------|-----------------------------|-------------------------|
| Pandas โ†’ CSV ์ €์žฅ      | ์ž„์‹œ ํŒŒ์ผ์— ๊ธฐ๋ก ํ›„ ๊ต์ฒด    | CSV ํŒŒ์ผ ๊นจ์ง ๋ฐฉ์ง€      |
| ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค ๋ณ‘๋ ฌ ์“ฐ๊ธฐ | atomic replace ๋ฐฉ์‹ ์‚ฌ์šฉ    | ์ถฉ๋Œ ์—†๋Š” ์•ˆ์ „ ์ €์žฅ     |
| ๋ฐ์ดํ„ฐ ํŒŒ์ดํ”„๋ผ์ธ ์ž‘์—… | ์ €์žฅ ์„ฑ๊ณต ์‹œ `_SUCCESS` ํ™•์ธ | ๋ฐ์ดํ„ฐ ์™„์ „์„ฑ ๋ณด์žฅ      |

---

## ๐Ÿ”„ ๋น„๊ต โ€“ ์œ ์‚ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํŠน์ง• ์ •๋ฆฌ

### [python-atomicwrites](https://github.com/untitaker/python-atomicwrites)
- ๊ฐ„ํŽธํ•œ API
- Windows ์ง€์›
- ํฌ๋กœ์Šค ํ”Œ๋žซํผ ํ˜ธํ™˜

### atomicwriter (๋ณธ ํ”„๋กœ์ ํŠธ)
- โœ… ๊ฒฝ๋Ÿ‰
- โœ… ํ”Œ๋Ÿฌ๊ทธ์ธ ์•„ํ‚คํ…์ฒ˜
- โœ… Pandas / Polars / Numpy ๋“ฑ ๋ฐ์ดํ„ฐ ๊ฐ์ฒด ์ค‘์‹ฌ ์ €์žฅ ์ง€์›

---

## โœ… ๋ผ์ด์„ ์Šค

Apache 2.0 โ€” ๊ธฐ์—… ๋ฐ ์ปค๋ฎค๋‹ˆํ‹ฐ ๋ชจ๋‘ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

---

## โœจ ์š”์•ฝ

**AtomicWriter**๋Š” ๋ถ„์„๋งŒํผ ์ค‘์š”ํ•œ **โ€œ์ €์žฅโ€ ๋‹จ๊ณ„๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ**ํ•˜๋Š” ๋„๊ตฌ์ž…๋‹ˆ๋‹ค.

ํŠนํžˆ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ์ด ์ค‘์š”ํ•œ ํ™˜๊ฒฝ์—์„œ  
(์˜ˆ: ๋จธ์‹ ๋Ÿฌ๋‹ ๋ฐฐ์น˜, ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค ๋ถ„์„, ์ค‘์š” ๋กœ๊ทธ ์ €์žฅ ๋“ฑ)  
**์ž‘์ง€๋งŒ ๊ฐ•๋ ฅํ•œ ํ•ด๊ฒฐ์ฑ…**์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“˜ ์‹œ๋‚˜๋ฆฌ์˜ค 1: Pandas CSV ์ €์žฅ ์ค‘ ์ž‘์—… ์ค‘๋‹จ
๋ฌธ์ œ ์ƒํ™ฉ:
ํ•œ ์‚ฌ์šฉ์ž๊ฐ€ Pandas๋กœ ๋Œ€์šฉ๋Ÿ‰ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ .csv ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋˜ ์ค‘, ์˜ˆ์ƒ์น˜ ๋ชปํ•œ ์ „์› ์ฐจ๋‹จ์ด๋‚˜ ์ปค๋„ ๊ฐ•์ œ ์ข…๋ฃŒ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ฒฐ๊ณผ ํŒŒ์ผ์€ 50MB ์ค‘ 3MB๋งŒ ์ €์žฅ๋œ ์ฑ„ ์†์ƒ๋˜์—ˆ๊ณ , ์ดํ›„ ์ฝ๊ธฐ๋„ ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

AtomicWriter๋กœ ํ•ด๊ฒฐ:
์ž„์‹œ ํŒŒ์ผ์— ๋จผ์ € ๊ธฐ๋ก ํ›„, ๋ชจ๋“  ์“ฐ๊ธฐ๊ฐ€ ์„ฑ๊ณตํ•ด์•ผ๋งŒ ์›๋ณธ๊ณผ ๊ต์ฒด๋ฉ๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ์ค‘๊ฐ„์— ๊บผ์ ธ๋„ ๊ธฐ์กด ํŒŒ์ผ์€ ๋ณด์กด๋˜๊ณ , ์†์ƒ๋œ ์ž„์‹œ ํŒŒ์ผ์€ ์ž๋™ ์ •๋ฆฌ๋˜์–ด ์•ˆ์ •์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“˜ ์‹œ๋‚˜๋ฆฌ์˜ค 2: ๋ฉ€ํ‹ฐํ”„๋กœ์„ธ์Šค ํ™˜๊ฒฝ์—์„œ ๊ฒฝ์Ÿ ์กฐ๊ฑด(Race Condition)
๋ฌธ์ œ ์ƒํ™ฉ:
Python multiprocessing ๊ธฐ๋ฐ˜ ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ ํŒŒ์ดํ”„๋ผ์ธ์—์„œ ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค๊ฐ€ ๋™์‹œ์— ๊ฐ™์€ ํŒŒ์ผ์„ ์ €์žฅํ•˜๋ฉฐ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ฒฐ๊ณผ์ ์œผ๋กœ ๋กœ๊ทธ ํŒŒ์ผ์ด ๋ฎ์–ด์“ฐ์—ฌ ๋ˆ„๋ฝ๋˜๊ฑฐ๋‚˜, ์ผ๋ถ€ JSON ํŒŒ์ผ์€ ํŒŒ์‹ฑํ•  ์ˆ˜ ์—†๋Š” ์†์ƒ๋œ ํ˜•ํƒœ๋กœ ์ €์žฅ๋์Šต๋‹ˆ๋‹ค.

AtomicWriter๋กœ ํ•ด๊ฒฐ:
ํŒŒ์ผ ์“ฐ๊ธฐ๋ฅผ atomic replace ๋ฐฉ์‹์œผ๋กœ ์ˆ˜ํ–‰ํ•˜๋ฉด, ํ•œ ๋ฒˆ์— ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค๋งŒ ์ตœ์ข… ๊ฒฝ๋กœ๋กœ ์ด๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์ด๋กœ์จ ๊ฒฝ์Ÿ ์กฐ๊ฑด ์—†์ด ์ถฉ๋Œ ์—†์ด ์ €์žฅ์ด ๋ณด์žฅ๋ฉ๋‹ˆ๋‹ค.

๐Ÿ“˜ ์‹œ๋‚˜๋ฆฌ์˜ค 3: ๋ฐ์ดํ„ฐ ํŒŒ์ดํ”„๋ผ์ธ ๊ฒ€์ฆ ๋ถˆ๊ฐ€
๋ฌธ์ œ ์ƒํ™ฉ:
ETL ์ž‘์—…์—์„œ .parquet ์ €์žฅ์ด ์™„๋ฃŒ๋๋Š”์ง€ ์—ฌ๋ถ€๋ฅผ ์ž๋™ ์‹œ์Šคํ…œ์ด ํŒ๋‹จํ•  ์ˆ˜ ์—†์–ด, ์†์ƒ๋˜๊ฑฐ๋‚˜ ๋ฏธ์™„์„ฑ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์Œ ๋‹จ๊ณ„์—์„œ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
๊ฒฐ๊ณผ์ ์œผ๋กœ ๋ชจ๋ธ ํ•™์Šต ๋ฐ์ดํ„ฐ์— ๊ฒฐ์ธก๊ฐ’์ด ํฌํ•จ๋˜์–ด ํ’ˆ์งˆ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

AtomicWriter๋กœ ํ•ด๊ฒฐ:
์ €์žฅ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์™„๋ฃŒ๋œ ๊ฒฝ์šฐ์—๋งŒ _SUCCESS ํ”Œ๋ž˜๊ทธ ํŒŒ์ผ์„ ํ•จ๊ป˜ ์ƒ์„ฑํ•˜๋„๋ก ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
ํ›„์† ๋‹จ๊ณ„๋Š” _SUCCESS ์œ ๋ฌด๋ฅผ ๊ธฐ์ค€์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ ํŒŒ์ดํ”„๋ผ์ธ์„ ๊ตฌ๋™ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ“˜ ์‹œ๋‚˜๋ฆฌ์˜ค 4: Polars DataFrame์„ S3๋กœ ์ €์žฅ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ
๋ฌธ์ œ ์ƒํ™ฉ:
Polars DataFrame์„ AWS S3์— ์ง์ ‘ ์ €์žฅํ•˜๋Š” ์ค‘๊ฐ„์— ConnectionError๊ฐ€ ๋ฐœ์ƒํ•˜์—ฌ S3์—๋Š” ๋ถ€๋ถ„์ ์œผ๋กœ ๊นจ์ง„ .parquet ํŒŒ์ผ์ด ์˜ฌ๋ผ๊ฐ”์Šต๋‹ˆ๋‹ค.
๋‹ค์Œ ๋ฒˆ ์‹คํ–‰์—์„œ ์ด ํŒŒ์ผ์„ ์žฌ์‚ฌ์šฉํ•˜๋ ค ํ–ˆ์ง€๋งŒ, S3์—์„œ ํŒŒ์ผ์ด ์†์ƒ๋œ ์ฑ„๋กœ ์กด์žฌํ•ด ์˜ค๋ฅ˜๋ฅผ ์œ ๋ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.

AtomicWriter๋กœ ํ•ด๊ฒฐ:
๋กœ์ปฌ ์ž„์‹œ ํŒŒ์ผ์— ์™„์ „ํžˆ ์ €์žฅ๋œ ํ›„์—๋งŒ S3 ์—…๋กœ๋“œ ๋˜๋Š” ๊ต์ฒด๊ฐ€ ์ˆ˜ํ–‰๋ฉ๋‹ˆ๋‹ค.
๋„คํŠธ์›Œํฌ ์ด์Šˆ๋‚˜ ๋””์Šคํฌ ์˜ค๋ฅ˜์—๋„ ์ตœ์ข… ํŒŒ์ผ์€ ํ•ญ์ƒ ์™„์ „ํ•œ ์ƒํƒœ๋กœ๋งŒ ์กด์žฌํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "atio",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": null,
    "keywords": "atomic, file, writer, pandas, polars, numpy, data",
    "author": null,
    "author_email": "Seo Jae Oh <seojaeohcoder@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/ab/09/40c88f1f3ed489fe368d730f8a2e3104e285865c52332c8de7e552077262/atio-1.0.0.tar.gz",
    "platform": null,
    "description": "# Atio \ud83d\udee1\ufe0f\r\n\r\n\uc548\uc804\ud558\uace0 **\uc6d0\uc790\uc801\uc778 \ud30c\uc77c \uc4f0\uae30**\ub97c \uc9c0\uc6d0\ud558\ub294 \uacbd\ub7c9 Python \ub77c\uc774\ube0c\ub7ec\ub9ac\uc785\ub2c8\ub2e4.  \r\nPandas, Polars, NumPy \ub4f1 \ub370\uc774\ud130 \uac1d\uccb4 \uc800\uc7a5 \uc2dc **\ud30c\uc77c \uc190\uc0c1 \uc5c6\uc774**, **\ud2b8\ub79c\uc7ad\uc158\ucc98\ub7fc \uc548\uc804\ud558\uac8c \ucc98\ub9ac**\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\r\n\r\n---\r\n\r\n## \ud83c\udf1f \uc8fc\uc694 \uae30\ub2a5\r\n\r\n- \u2705 \uc784\uc2dc \ub514\ub809\ud1a0\ub9ac \uc2a4\ud14c\uc774\uc9d5 \ud6c4 **\uc6d0\uc790\uc801 \ud30c\uc77c \uad50\uccb4**  \r\n- \ud83d\udce6 Pandas, Polars, NumPy \ub4f1 \ub2e4\uc591\ud55c \ub370\uc774\ud130 \uac1d\uccb4 \uc9c0\uc6d0  \r\n- \ud83d\udccd `_SUCCESS` \ud50c\ub798\uadf8 \ud30c\uc77c \uc0dd\uc131 \u2014 \uc800\uc7a5 \uc644\ub8cc \uc5ec\ubd80 \ud45c\uc2dc  \r\n- \ud83d\udee0 \uc2e4\ud328 \uc2dc **\uc6d0\ubcf8 \ud30c\uc77c \ubcf4\uc874**, \uc784\uc2dc \ud30c\uc77c \uc790\ub3d9 \uc815\ub9ac  \r\n- \ud83e\udde9 \ud50c\ub7ec\uadf8\uc778 \uc544\ud0a4\ud14d\ucc98\ub85c **\ud655\uc7a5\uc131 \uc88b\uc74c**\r\n- \ud83d\udd0d **\uc131\ub2a5 \uc9c4\ub2e8 \ub85c\uae45** \u2014 \uac01 \ub2e8\uacc4\ubcc4 \uc2e4\ud589 \uc2dc\uac04 \uce21\uc815 \ubc0f \ubcd1\ubaa9\uc810 \ubd84\uc11d\r\n\r\n---\r\n\r\n## \ud83d\udd0d \uc131\ub2a5 \uc9c4\ub2e8 \ub85c\uae45 (NEW!)\r\n\r\nAtio\ub294 \uc774\uc81c **\uc131\ub2a5 \uc9c4\ub2e8 \ub85c\uae45** \uae30\ub2a5\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4. `verbose=True` \uc635\uc158\uc744 \uc0ac\uc6a9\ud558\uba74 \uac01 \ub2e8\uacc4\ubcc4 \uc2e4\ud589 \uc2dc\uac04\uc744 \uce21\uc815\ud558\uc5ec \ubcd1\ubaa9\uc810\uc744 \uc815\ud655\ud788 \ud30c\uc545\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\r\n\r\n### \uae30\ubcf8 \uc0ac\uc6a9\ubc95 (\uac04\ub2e8\ud55c \uc815\ubcf4\ub9cc):\r\n```python\r\nimport atio as aw\r\nimport pandas as pd\r\n\r\ndf = pd.DataFrame({\"a\": [1, 2, 3]})\r\n\r\n# \uae30\ubcf8 \uc0ac\uc6a9\ubc95 - \uac04\ub2e8\ud55c \uc131\uacf5/\uc2e4\ud328 \uc815\ubcf4\ub9cc\r\naw.write(df, \"output.parquet\", format=\"parquet\")\r\n```\r\n\r\n**\ucd9c\ub825 \uc608\uc2dc:**\r\n```\r\n[INFO] \uc784\uc2dc \ub514\ub809\ud1a0\ub9ac \uc0dd\uc131: /tmp/tmp_xxx\r\n[INFO] \uc784\uc2dc \ud30c\uc77c \uacbd\ub85c: /tmp/tmp_xxx/output.parquet\r\n[INFO] \uc0ac\uc6a9\ud560 writer: to_parquet (format: parquet)\r\n[INFO] \ub370\uc774\ud130 \uc784\uc2dc \ud30c\uc77c\uc5d0 \uc800\uc7a5 \uc644\ub8cc: /tmp/tmp_xxx/output.parquet\r\n[INFO] \uc6d0\uc790\uc801 \uad50\uccb4 \uc644\ub8cc: /tmp/tmp_xxx/output.parquet -> output.parquet\r\n[INFO] _SUCCESS \ud50c\ub798\uadf8 \ud30c\uc77c \uc0dd\uc131: output.parquet._SUCCESS\r\n[INFO] Atomic write completed successfully (took 0.2359s)\r\n```\r\n\r\n### \uc0c1\uc138 \uc9c4\ub2e8 \ubaa8\ub4dc (verbose=True):\r\n```python\r\n# \uc0c1\uc138\ud55c \uc131\ub2a5 \uc9c4\ub2e8 \uc815\ubcf4 \ucd9c\ub825\r\naw.write(df, \"output.parquet\", format=\"parquet\", verbose=True)\r\n```\r\n\r\n**\ucd9c\ub825 \uc608\uc2dc:**\r\n```\r\n[INFO] \uc784\uc2dc \ub514\ub809\ud1a0\ub9ac \uc0dd\uc131: /tmp/tmp_xxx\r\n[INFO] \uc784\uc2dc \ud30c\uc77c \uacbd\ub85c: /tmp/tmp_xxx/output.parquet\r\n[INFO] \uc0ac\uc6a9\ud560 writer: to_parquet (format: parquet)\r\n[INFO] \ub370\uc774\ud130 \uc784\uc2dc \ud30c\uc77c\uc5d0 \uc800\uc7a5 \uc644\ub8cc: /tmp/tmp_xxx/output.parquet\r\n[INFO] \uc6d0\uc790\uc801 \uad50\uccb4 \uc644\ub8cc: /tmp/tmp_xxx/output.parquet -> output.parquet\r\n[INFO] _SUCCESS \ud50c\ub798\uadf8 \ud30c\uc77c \uc0dd\uc131: output.parquet._SUCCESS\r\n[DEBUG] Atomic write step timings (SUCCESS): setup=0.0012s, write_call=0.2345s, replace=0.0001s, success_flag=0.0001s, total=0.2359s\r\n```\r\n\r\n### \uc624\ub958 \ubc1c\uc0dd \uc2dc (\uae30\ubcf8 \uc0ac\uc6a9\ubc95):\r\n```\r\n[INFO] \uc784\uc2dc \ub514\ub809\ud1a0\ub9ac \uc0dd\uc131: /tmp/tmp_xxx\r\n[INFO] \uc784\uc2dc \ud30c\uc77c \uacbd\ub85c: /tmp/tmp_xxx/output.parquet\r\n[INFO] \uc0ac\uc6a9\ud560 writer: to_parquet (format: parquet)\r\n[ERROR] \uc784\uc2dc \ud30c\uc77c \uc800\uc7a5 \uc911 \uc608\uc678 \ubc1c\uc0dd: [Errno 28] No space left on device\r\n[INFO] Atomic write failed during write stage (took 0.1246s, error: OSError)\r\n```\r\n\r\n### \uc624\ub958 \ubc1c\uc0dd \uc2dc (verbose=True):\r\n```\r\n[INFO] \uc784\uc2dc \ub514\ub809\ud1a0\ub9ac \uc0dd\uc131: /tmp/tmp_xxx\r\n[INFO] \uc784\uc2dc \ud30c\uc77c \uacbd\ub85c: /tmp/tmp_xxx/output.parquet\r\n[INFO] \uc0ac\uc6a9\ud560 writer: to_parquet (format: parquet)\r\n[ERROR] \uc784\uc2dc \ud30c\uc77c \uc800\uc7a5 \uc911 \uc608\uc678 \ubc1c\uc0dd: [Errno 28] No space left on device\r\n[DEBUG] Atomic write step timings (ERROR during write): setup=0.0012s, write_call=0.1234s (\uc2e4\ud328), replace=N/A, success_flag=N/A, total=0.1246s, error_type=OSError\r\n```\r\n\r\n**\uce21\uc815\ub418\ub294 \ub2e8\uacc4:**\r\n- `setup`: \uc784\uc2dc \ud3f4\ub354 \uc0dd\uc131 \ubc0f \ucd08\uae30 \uc124\uc815\r\n- `write_call`: \uc2e4\uc81c \ub370\uc774\ud130 \uc4f0\uae30 \ud568\uc218 \ud638\ucd9c (\ub300\ubd80\ubd84\uc758 \uc2dc\uac04 \uc18c\uc694)\r\n- `replace`: \uc6d0\uc790\uc801 \ud30c\uc77c \uad50\uccb4\r\n- `success_flag`: _SUCCESS \ud50c\ub798\uadf8 \ud30c\uc77c \uc0dd\uc131\r\n- `total`: \uc804\uccb4 \uc791\uc5c5 \uc2dc\uac04\r\n\r\n**\uc9c0\uc6d0\ud558\ub294 \uc624\ub958 \uc0c1\ud669:**\r\n- \u2705 **KeyboardInterrupt**: \uc778\ud130\ub7fd\ud2b8 \ubc1c\uc0dd \uc2dc\uc810\uacfc \uc18c\uc694 \uc2dc\uac04 \ud45c\uc2dc\r\n- \u2705 **\uad8c\ud55c \uc624\ub958**: \ud30c\uc77c \uc2dc\uc2a4\ud15c \uad8c\ud55c \ubb38\uc81c \uc9c4\ub2e8\r\n- \u2705 **\ub514\uc2a4\ud06c \uacf5\uac04 \ubd80\uc871**: \uc800\uc7a5 \uacf5\uac04 \ubd80\uc871 \uc0c1\ud669 \uc9c4\ub2e8\r\n- \u2705 **\uba54\ubaa8\ub9ac \ubd80\uc871**: \uba54\ubaa8\ub9ac \uc555\ubc15 \uc0c1\ud669 \uc9c4\ub2e8\r\n- \u2705 **\ub124\ud2b8\uc6cc\ud06c \uc624\ub958**: \ub124\ud2b8\uc6cc\ud06c \ub4dc\ub77c\uc774\ube0c \uc811\uadfc \ubb38\uc81c \uc9c4\ub2e8\r\n- \u2705 **\uc9c0\uc6d0\ud558\uc9c0 \uc54a\ub294 \ud615\uc2dd**: \uc798\ubabb\ub41c \ud30c\uc77c \ud615\uc2dd \uc9c0\uc815 \uc2dc \uc9c4\ub2e8\r\n- \u2705 **\ub3d9\uc2dc \uc811\uadfc \uc624\ub958**: \uba40\ud2f0\uc2a4\ub808\ub529 \ud658\uacbd\uc5d0\uc11c\uc758 \ucda9\ub3cc \uc9c4\ub2e8\r\n\r\n**\uc7a5\uc810:**\r\n- \ud83c\udfaf **\uc815\ud655\ud55c \ubcd1\ubaa9\uc810 \ud30c\uc545**: Atio \uc624\ubc84\ud5e4\ub4dc vs \uc2e4\uc81c \uc4f0\uae30 \uc791\uc5c5 \uc2dc\uac04 \uad6c\ubd84\r\n- \ud83d\udd27 **\uc131\ub2a5 \ucd5c\uc801\ud654 \uac00\uc774\ub4dc**: \uc5b4\ub290 \ub2e8\uacc4\uc5d0\uc11c \uc2dc\uac04\uc774 \ub9ce\uc774 \uc18c\uc694\ub418\ub294\uc9c0 \uba85\ud655\ud788 \ud45c\uc2dc\r\n- \ud83d\udc1b **\ub514\ubc84\uae45 \uc2dc\uac04 \ub2e8\ucd95**: \ubb38\uc81c\uc758 \uc6d0\uc778\uc744 \ube60\ub974\uac8c \ud30c\uc545 \uac00\ub2a5\r\n- \ud83d\udcca **\uc131\ub2a5 \ubaa8\ub2c8\ud130\ub9c1**: \ub300\uc6a9\ub7c9 \ub370\uc774\ud130 \ucc98\ub9ac \uc2dc \uc131\ub2a5 \ucd94\uc801\r\n- \ud83d\udea8 **\uc624\ub958 \uc9c4\ub2e8**: \uc2e4\ud328 \uc0c1\ud669\uc5d0\uc11c\ub3c4 \uc815\ud655\ud55c \uc6d0\uc778\uacfc \ubc1c\uc0dd \uc2dc\uc810 \ud30c\uc545\r\n\r\n---\r\n\r\n## \ud83e\udde0 \uc65c \uc774 \ub3c4\uad6c\uac00 \uc815\ub9d0 \uc911\uc694\ud55c\uac00\uc694?\r\n\r\nNumPy\ub098 Pandas\ub294 \ub370\uc774\ud130 \ubd84\uc11d\uc5d0\uc11c\ub294 \ucd5c\uc801\uc774\uc9c0\ub9cc, **\ud30c\uc77c\ub85c \uc800\uc7a5\ud560 \ub54c\ub294 \uc544\ub798\uc640 \uac19\uc740 \uc704\ud5d8**\uc774 \uc788\uc2b5\ub2c8\ub2e4:\r\n\r\n1. **\ud30c\uc77c \uc77c\ubd80\ub9cc \uc800\uc7a5\ub418\uc5b4 \uae68\uc9c8 \uc218 \uc788\uc74c** \u2014 \uac15\uc81c \uc885\ub8cc\ub098 \uc624\ub958 \uc2dc\r\n2. **\ub3d9\uc2dc \uc4f0\uae30 \ucda9\ub3cc** \u2014 \uba40\ud2f0\ud504\ub85c\uc138\uc2a4 \ud658\uacbd\uc5d0\uc11c \ud30c\uc77c\uc774 \uc5c9\ud0ac \uc218 \uc788\uc74c\r\n3. **\ud50c\ub7ab\ud3fc \uac04 \ub3d9\uc791 \ucc28\uc774** \u2014 Windows\uc640 Linux/macOS\uc5d0\uc11c \ud30c\uc77c \uc2dc\uc2a4\ud15c \ub3d9\uc791\uc774 \ub2e4\ub984\r\n\r\nAtomicWriter\ub294 \uc784\uc2dc \ud30c\uc77c\uc5d0 \uc4f0\uace0 **\ub2e8\uc77c `rename()`/`replace()` \uc791\uc5c5\uc73c\ub85c \uad50\uccb4**\ud569\ub2c8\ub2e4.  \r\n\uc774 \ubc29\uc2dd\uc740 **\u201c\uc644\uc804\ud788 \uc800\uc7a5\ub418\uac70\ub098 \uc804\ud600 \uc800\uc7a5\ub418\uc9c0 \uc54a\ub294\u201d** \uc6d0\uc790\uc131(atomicity)\uc744 \ubcf4\uc7a5\ud558\uba70,  \r\n- POSIX: `os.replace` (atomic), `fsync`  \r\n- Windows: `MoveFileEx`, `Commit`  \r\n\ub97c \ud65c\uc6a9\ud558\uc5ec \ud30c\uc77c\uc774 **\ud56d\uc0c1 \uc77c\uad00\ub41c \uc0c1\ud0dc**\ub97c \uc720\uc9c0\ud558\ub3c4\ub85d \ud569\ub2c8\ub2e4 :contentReference[oaicite:1]{index=1}.\r\n\r\n---\r\n\r\n## \u2699\ufe0f \uc124\uce58\r\n\r\n```bash\r\npip install atomicwriter\r\n\r\n## \ud83d\udee0\ufe0f \uc0ac\uc6a9 \uc608\uc81c\r\n\r\n```python\r\nimport atomicwriter as aw\r\nimport pandas as pd\r\n\r\ndf = pd.DataFrame({\"a\": [1, 2, 3]})\r\n\r\n# \uae30\ubcf8 \uc0ac\uc6a9\ubc95\r\naw.write(df, \"output.parquet\", format=\"parquet\")\r\n# \u2502\u2192 \uc784\uc2dc \ud30c\uc77c \uc791\uc131 \u2192 \uc6d0\uc790\uc801 \uad50\uccb4 \u2192 _SUCCESS \uc0dd\uc131\r\n# \u2502\u2192 \uc2e4\ud328 \uc2dc \uc6d0\ubcf8 \ubcf4\uc874, \uc784\uc2dc \ud30c\uc77c \uc790\ub3d9 \uc815\ub9ac\r\n\r\n# \uc0c1\uc138 \uc131\ub2a5 \uc9c4\ub2e8 \ub85c\uae45 \ud65c\uc131\ud654\r\naw.write(df, \"output_verbose.parquet\", format=\"parquet\", verbose=True)\r\n# \u2502\u2192 \uac01 \ub2e8\uacc4\ubcc4 \uc2e4\ud589 \uc2dc\uac04 \uce21\uc815 \ubc0f \ub85c\uadf8 \ucd9c\ub825\r\n\r\n# \uc9c4\ud589\ub3c4 \ud45c\uc2dc\uc640 \ud568\uaed8 \uc0ac\uc6a9\r\naw.write(df, \"output_progress.parquet\", format=\"parquet\", show_progress=True)\r\n# \u2502\u2192 \uc2e4\uc2dc\uac04 \uc9c4\ud589\ub3c4 \ud45c\uc2dc\r\n\r\n# \ubaa8\ub4e0 \uc635\uc158 \uc870\ud569\r\naw.write(df, \"output_full.parquet\", format=\"parquet\", \r\n         verbose=True, show_progress=True)\r\n# \u2502\u2192 \uc131\ub2a5 \uc9c4\ub2e8 + \uc9c4\ud589\ub3c4 \ud45c\uc2dc\r\n```\r\n\r\n## \ud83d\udca1 \ube45\ub370\uc774\ud130 \uc6cc\ud06c\ud50c\ub85c\uc6b0\uc5d0\uc11c \ud65c\uc6a9 \uc2dc\ub098\ub9ac\uc624\r\n\r\n| \uc2dc\ub098\ub9ac\uc624               | \ud574\uacb0 \ubc29\ubc95                   | \uc7a5\uc810                    |\r\n|------------------------|-----------------------------|-------------------------|\r\n| Pandas \u2192 CSV \uc800\uc7a5      | \uc784\uc2dc \ud30c\uc77c\uc5d0 \uae30\ub85d \ud6c4 \uad50\uccb4    | CSV \ud30c\uc77c \uae68\uc9d0 \ubc29\uc9c0      |\r\n| \uba40\ud2f0\ud504\ub85c\uc138\uc2a4 \ubcd1\ub82c \uc4f0\uae30 | atomic replace \ubc29\uc2dd \uc0ac\uc6a9    | \ucda9\ub3cc \uc5c6\ub294 \uc548\uc804 \uc800\uc7a5     |\r\n| \ub370\uc774\ud130 \ud30c\uc774\ud504\ub77c\uc778 \uc791\uc5c5 | \uc800\uc7a5 \uc131\uacf5 \uc2dc `_SUCCESS` \ud655\uc778 | \ub370\uc774\ud130 \uc644\uc804\uc131 \ubcf4\uc7a5      |\r\n\r\n---\r\n\r\n## \ud83d\udd04 \ube44\uad50 \u2013 \uc720\uc0ac \ub77c\uc774\ube0c\ub7ec\ub9ac \ud2b9\uc9d5 \uc815\ub9ac\r\n\r\n### [python-atomicwrites](https://github.com/untitaker/python-atomicwrites)\r\n- \uac04\ud3b8\ud55c API\r\n- Windows \uc9c0\uc6d0\r\n- \ud06c\ub85c\uc2a4 \ud50c\ub7ab\ud3fc \ud638\ud658\r\n\r\n### atomicwriter (\ubcf8 \ud504\ub85c\uc81d\ud2b8)\r\n- \u2705 \uacbd\ub7c9\r\n- \u2705 \ud50c\ub7ec\uadf8\uc778 \uc544\ud0a4\ud14d\ucc98\r\n- \u2705 Pandas / Polars / Numpy \ub4f1 \ub370\uc774\ud130 \uac1d\uccb4 \uc911\uc2ec \uc800\uc7a5 \uc9c0\uc6d0\r\n\r\n---\r\n\r\n## \u2705 \ub77c\uc774\uc120\uc2a4\r\n\r\nApache 2.0 \u2014 \uae30\uc5c5 \ubc0f \ucee4\ubba4\ub2c8\ud2f0 \ubaa8\ub450 \uc790\uc720\ub86d\uac8c \uc0ac\uc6a9 \uac00\ub2a5\r\n\r\n---\r\n\r\n## \u2728 \uc694\uc57d\r\n\r\n**AtomicWriter**\ub294 \ubd84\uc11d\ub9cc\ud07c \uc911\uc694\ud55c **\u201c\uc800\uc7a5\u201d \ub2e8\uacc4\ub97c \uc548\uc804\ud558\uac8c \ucc98\ub9ac**\ud558\ub294 \ub3c4\uad6c\uc785\ub2c8\ub2e4.\r\n\r\n\ud2b9\ud788 \ub370\uc774\ud130 \ubb34\uacb0\uc131\uc774 \uc911\uc694\ud55c \ud658\uacbd\uc5d0\uc11c  \r\n(\uc608: \uba38\uc2e0\ub7ec\ub2dd \ubc30\uce58, \uba40\ud2f0\ud504\ub85c\uc138\uc2a4 \ubd84\uc11d, \uc911\uc694 \ub85c\uadf8 \uc800\uc7a5 \ub4f1)  \r\n**\uc791\uc9c0\ub9cc \uac15\ub825\ud55c \ud574\uacb0\ucc45**\uc744 \uc81c\uacf5\ud569\ub2c8\ub2e4.\r\n\r\n\ud83d\udcd8 \uc2dc\ub098\ub9ac\uc624 1: Pandas CSV \uc800\uc7a5 \uc911 \uc791\uc5c5 \uc911\ub2e8\r\n\ubb38\uc81c \uc0c1\ud669:\r\n\ud55c \uc0ac\uc6a9\uc790\uac00 Pandas\ub85c \ub300\uc6a9\ub7c9 \ubd84\uc11d \uacb0\uacfc\ub97c .csv \ud30c\uc77c\ub85c \uc800\uc7a5\ud558\ub358 \uc911, \uc608\uc0c1\uce58 \ubabb\ud55c \uc804\uc6d0 \ucc28\ub2e8\uc774\ub098 \ucee4\ub110 \uac15\uc81c \uc885\ub8cc\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.\r\n\uacb0\uacfc \ud30c\uc77c\uc740 50MB \uc911 3MB\ub9cc \uc800\uc7a5\ub41c \ucc44 \uc190\uc0c1\ub418\uc5c8\uace0, \uc774\ud6c4 \uc77d\uae30\ub3c4 \ub418\uc9c0 \uc54a\uc558\uc2b5\ub2c8\ub2e4.\r\n\r\nAtomicWriter\ub85c \ud574\uacb0:\r\n\uc784\uc2dc \ud30c\uc77c\uc5d0 \uba3c\uc800 \uae30\ub85d \ud6c4, \ubaa8\ub4e0 \uc4f0\uae30\uac00 \uc131\uacf5\ud574\uc57c\ub9cc \uc6d0\ubcf8\uacfc \uad50\uccb4\ub429\ub2c8\ub2e4.\r\n\ub530\ub77c\uc11c \uc911\uac04\uc5d0 \uaebc\uc838\ub3c4 \uae30\uc874 \ud30c\uc77c\uc740 \ubcf4\uc874\ub418\uace0, \uc190\uc0c1\ub41c \uc784\uc2dc \ud30c\uc77c\uc740 \uc790\ub3d9 \uc815\ub9ac\ub418\uc5b4 \uc548\uc815\uc131\uc744 \ud655\ubcf4\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\r\n\r\n\ud83d\udcd8 \uc2dc\ub098\ub9ac\uc624 2: \uba40\ud2f0\ud504\ub85c\uc138\uc2a4 \ud658\uacbd\uc5d0\uc11c \uacbd\uc7c1 \uc870\uac74(Race Condition)\r\n\ubb38\uc81c \uc0c1\ud669:\r\nPython multiprocessing \uae30\ubc18 \ub370\uc774\ud130 \uc218\uc9d1 \ud30c\uc774\ud504\ub77c\uc778\uc5d0\uc11c \uc5ec\ub7ec \ud504\ub85c\uc138\uc2a4\uac00 \ub3d9\uc2dc\uc5d0 \uac19\uc740 \ud30c\uc77c\uc744 \uc800\uc7a5\ud558\uba70 \ucda9\ub3cc\uc774 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.\r\n\uacb0\uacfc\uc801\uc73c\ub85c \ub85c\uadf8 \ud30c\uc77c\uc774 \ub36e\uc5b4\uc4f0\uc5ec \ub204\ub77d\ub418\uac70\ub098, \uc77c\ubd80 JSON \ud30c\uc77c\uc740 \ud30c\uc2f1\ud560 \uc218 \uc5c6\ub294 \uc190\uc0c1\ub41c \ud615\ud0dc\ub85c \uc800\uc7a5\ub410\uc2b5\ub2c8\ub2e4.\r\n\r\nAtomicWriter\ub85c \ud574\uacb0:\r\n\ud30c\uc77c \uc4f0\uae30\ub97c atomic replace \ubc29\uc2dd\uc73c\ub85c \uc218\ud589\ud558\uba74, \ud55c \ubc88\uc5d0 \ud558\ub098\uc758 \ud504\ub85c\uc138\uc2a4\ub9cc \ucd5c\uc885 \uacbd\ub85c\ub85c \uc774\ub3d9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\r\n\uc774\ub85c\uc368 \uacbd\uc7c1 \uc870\uac74 \uc5c6\uc774 \ucda9\ub3cc \uc5c6\uc774 \uc800\uc7a5\uc774 \ubcf4\uc7a5\ub429\ub2c8\ub2e4.\r\n\r\n\ud83d\udcd8 \uc2dc\ub098\ub9ac\uc624 3: \ub370\uc774\ud130 \ud30c\uc774\ud504\ub77c\uc778 \uac80\uc99d \ubd88\uac00\r\n\ubb38\uc81c \uc0c1\ud669:\r\nETL \uc791\uc5c5\uc5d0\uc11c .parquet \uc800\uc7a5\uc774 \uc644\ub8cc\ub410\ub294\uc9c0 \uc5ec\ubd80\ub97c \uc790\ub3d9 \uc2dc\uc2a4\ud15c\uc774 \ud310\ub2e8\ud560 \uc218 \uc5c6\uc5b4, \uc190\uc0c1\ub418\uac70\ub098 \ubbf8\uc644\uc131\ub41c \ub370\uc774\ud130\ub97c \ub2e4\uc74c \ub2e8\uacc4\uc5d0\uc11c \uadf8\ub300\ub85c \uc0ac\uc6a9\ud588\uc2b5\ub2c8\ub2e4.\r\n\uacb0\uacfc\uc801\uc73c\ub85c \ubaa8\ub378 \ud559\uc2b5 \ub370\uc774\ud130\uc5d0 \uacb0\uce21\uac12\uc774 \ud3ec\ud568\ub418\uc5b4 \ud488\uc9c8 \uc800\ud558\uac00 \ubc1c\uc0dd\ud588\uc2b5\ub2c8\ub2e4.\r\n\r\nAtomicWriter\ub85c \ud574\uacb0:\r\n\uc800\uc7a5\uc774 \uc131\uacf5\uc801\uc73c\ub85c \uc644\ub8cc\ub41c \uacbd\uc6b0\uc5d0\ub9cc _SUCCESS \ud50c\ub798\uadf8 \ud30c\uc77c\uc744 \ud568\uaed8 \uc0dd\uc131\ud558\ub3c4\ub85d \uc124\uc815\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\r\n\ud6c4\uc18d \ub2e8\uacc4\ub294 _SUCCESS \uc720\ubb34\ub97c \uae30\uc900\uc73c\ub85c \uc548\uc804\ud558\uac8c \ud30c\uc774\ud504\ub77c\uc778\uc744 \uad6c\ub3d9\ud560 \uc218 \uc788\uc2b5\ub2c8\ub2e4.\r\n\r\n\ud83d\udcd8 \uc2dc\ub098\ub9ac\uc624 4: Polars DataFrame\uc744 S3\ub85c \uc800\uc7a5 \uc911 \uc624\ub958 \ubc1c\uc0dd\r\n\ubb38\uc81c \uc0c1\ud669:\r\nPolars DataFrame\uc744 AWS S3\uc5d0 \uc9c1\uc811 \uc800\uc7a5\ud558\ub294 \uc911\uac04\uc5d0 ConnectionError\uac00 \ubc1c\uc0dd\ud558\uc5ec S3\uc5d0\ub294 \ubd80\ubd84\uc801\uc73c\ub85c \uae68\uc9c4 .parquet \ud30c\uc77c\uc774 \uc62c\ub77c\uac14\uc2b5\ub2c8\ub2e4.\r\n\ub2e4\uc74c \ubc88 \uc2e4\ud589\uc5d0\uc11c \uc774 \ud30c\uc77c\uc744 \uc7ac\uc0ac\uc6a9\ud558\ub824 \ud588\uc9c0\ub9cc, S3\uc5d0\uc11c \ud30c\uc77c\uc774 \uc190\uc0c1\ub41c \ucc44\ub85c \uc874\uc7ac\ud574 \uc624\ub958\ub97c \uc720\ubc1c\ud588\uc2b5\ub2c8\ub2e4.\r\n\r\nAtomicWriter\ub85c \ud574\uacb0:\r\n\ub85c\uceec \uc784\uc2dc \ud30c\uc77c\uc5d0 \uc644\uc804\ud788 \uc800\uc7a5\ub41c \ud6c4\uc5d0\ub9cc S3 \uc5c5\ub85c\ub4dc \ub610\ub294 \uad50\uccb4\uac00 \uc218\ud589\ub429\ub2c8\ub2e4.\r\n\ub124\ud2b8\uc6cc\ud06c \uc774\uc288\ub098 \ub514\uc2a4\ud06c \uc624\ub958\uc5d0\ub3c4 \ucd5c\uc885 \ud30c\uc77c\uc740 \ud56d\uc0c1 \uc644\uc804\ud55c \uc0c1\ud0dc\ub85c\ub9cc \uc874\uc7ac\ud558\uac8c \ub429\ub2c8\ub2e4.\r\n",
    "bugtrack_url": null,
    "license": "Apache-2.0",
    "summary": "Safe atomic file writer for Pandas, Polars, NumPy, and other data objects",
    "version": "1.0.0",
    "project_urls": {
        "Homepage": "https://github.com/seojaeohcode/atomic-writer"
    },
    "split_keywords": [
        "atomic",
        " file",
        " writer",
        " pandas",
        " polars",
        " numpy",
        " data"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "1f719d6d8dcbdbd33c177f04da9065122ef220ac799bb01f0977d580bb7d442e",
                "md5": "8977d01e75b0e81a1bead503724ffee9",
                "sha256": "78987d8959eda0c467401a0635d9c76bfa5407d3423c94633f197c974553755f"
            },
            "downloads": -1,
            "filename": "atio-1.0.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "8977d01e75b0e81a1bead503724ffee9",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 23193,
            "upload_time": "2025-08-02T08:57:22",
            "upload_time_iso_8601": "2025-08-02T08:57:22.429264Z",
            "url": "https://files.pythonhosted.org/packages/1f/71/9d6d8dcbdbd33c177f04da9065122ef220ac799bb01f0977d580bb7d442e/atio-1.0.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "ab0940c88f1f3ed489fe368d730f8a2e3104e285865c52332c8de7e552077262",
                "md5": "6432ddcb8e5a9df4b09eaf4a2fa426fa",
                "sha256": "7f1500863affcfd2dbcb412e47a0b9f771ffea0629bf59e68cfd1cbd4b262e41"
            },
            "downloads": -1,
            "filename": "atio-1.0.0.tar.gz",
            "has_sig": false,
            "md5_digest": "6432ddcb8e5a9df4b09eaf4a2fa426fa",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 32295,
            "upload_time": "2025-08-02T08:57:23",
            "upload_time_iso_8601": "2025-08-02T08:57:23.908860Z",
            "url": "https://files.pythonhosted.org/packages/ab/09/40c88f1f3ed489fe368d730f8a2e3104e285865c52332c8de7e552077262/atio-1.0.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-02 08:57:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "seojaeohcode",
    "github_project": "atomic-writer",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "requirements": [
        {
            "name": "pandas",
            "specs": []
        },
        {
            "name": "pyarrow",
            "specs": []
        },
        {
            "name": "polars",
            "specs": []
        },
        {
            "name": "pytest",
            "specs": []
        },
        {
            "name": "build",
            "specs": []
        },
        {
            "name": "twine",
            "specs": []
        }
    ],
    "lcname": "atio"
}
        
Elapsed time: 2.71546s