Metadata-Version: 2.4
Name: jsonquotefixer
Version: 0.3.0
Summary: Fixer for broken/unescaped quotes in pseudo-JSON text
Project-URL: Homepage, https://github.com/abzb1/jsonfixer
Project-URL: Issues, https://github.com/abzb1/jsonfixer/issues
Author-email: Hongseok Oh <cxv0519@gmail.com>
License: The MIT License
        
        Copyright (c) 2025 Hongseok Oh
        
        Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
License-File: LICENSE
Keywords: fix,json,pseudo-json,quotes,repair,structured output
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.8
Provides-Extra: dev
Requires-Dist: pre-commit>=4.6.0; extra == 'dev'
Requires-Dist: pytest>=9.0.3; extra == 'dev'
Description-Content-Type: text/markdown

# jsonfixer

A small utility to repair broken / pseudo-JSON strings that AI models often
produce, so they can be parsed by Python's built-in `json` module.

## Motivation

LLM outputs frequently contain JSON that *looks* correct but is actually invalid:

- Unescaped inner double quotes inside string values
- Raw control characters (literal newlines, tabs, etc.) inside strings
- Smart/curly quotes (`“ ” ‘ ’`) instead of straight quotes
- The whole JSON wrapped in Markdown triple-backtick code fences
- The whole JSON returned as a quoted string with escaped `\n` sequences

For example, the following is **not** valid JSON and `json.loads` will fail:

```json
{
    "key1": "value1",
    "key2": "value2 is behind the "value1", that is good"
}
```

`jsonfixer` detects and repairs these common patterns so you can reliably
call `json.loads()` on the result.

## Features

- Escapes stray inner double quotes inside string values (`"` → `\"`)
- Converts literal control characters inside strings to proper JSON escapes
  (`\n`, `\t`, `\r`, `\b`, `\f`, and `\u00XX` for other `< 0x20` code points)
- Normalizes CRLF (`\r\n`) inside strings to `\n`
- Optional extraction of JSON from Markdown code fences (```` ```json ... ``` ````)
- Optional replacement of smart quotes (`“ ” ‘ ’`) with straight quotes (`" '`)
- Leaves already-valid JSON unchanged
- Pure Python, no runtime dependencies

## Installation

```bash
pip install jsonquotefixer
```

## Usage

### Basic example

```python
import json
from jsonfixer import fix_quotes

broken = '{"title": "The "Great" Gatsby", "author": "F. Scott Fitzgerald"}'

json.loads(broken)          # raises json.JSONDecodeError

fixed = fix_quotes(broken)
json.loads(fixed)
# {'title': 'The "Great" Gatsby', 'author': 'F. Scott Fitzgerald'}
```

### Extracting from a Markdown code block

Pass `parse_code=True` when the model wraps the JSON in triple backticks,
or returns it as a JSON-encoded string with escaped newlines:

```python
from jsonfixer import fix_quotes

raw = '```json\n{"a": "hello"}\n```'
fix_quotes(raw, parse_code=True)
# '{"a": "hello"}'
```

### Replacing smart quotes

Pass `replace_smart=True` to convert curly quotes to straight quotes before
the fix-up step runs:

```python
from jsonfixer import fix_quotes

raw = '{“a”: “hello”}'
fix_quotes(raw, replace_smart=True)
# '{"a": "hello"}'
```

### All options combined

```python
fix_quotes(raw, parse_code=True, replace_smart=True)
```

## API

### `fix_quotes(s, parse_code=False, replace_smart=False) -> str`

Main entry point. Returns a repaired JSON string.

| Argument        | Type   | Default | Description                                                                 |
|-----------------|--------|---------|-----------------------------------------------------------------------------|
| `s`             | `str`  | —       | The broken / pseudo-JSON string to repair.                                  |
| `parse_code`    | `bool` | `False` | Extract JSON from Markdown code fences, and unwrap outer JSON string quotes.|
| `replace_smart` | `bool` | `False` | Replace smart quotes (`“ ” ‘ ’`) with straight quotes (`" '`) before fixing.|

### `parse_codeblock(s) -> str | None`

Extracts the content of the first triple-backtick code fence in `s`
(with or without a language tag). Also handles the case where newlines
appear as the literal two-character sequence `\n`. Returns `None` if no
code fence is found.

### `replace_smart_quotes(s) -> str`

Returns `s` with smart quotes replaced by their straight-quote equivalents.
Does not perform any other repair.

## Development

### Setting up

```bash
git clone https://github.com/abzb1/jsonfixer.git
cd jsonfixer
pip install -e '.[dev]'
```

### Running the tests

Tests are written with `pytest`:

```bash
pytest
```

Or, to run a specific test and see verbose output:

```bash
pytest tests/test_fix_quotes.py -v
pytest tests/test_fix_quotes.py::test_valid_json_unchanged -v
```

### Pre-commit hooks

The repository ships with a `.pre-commit-config.yaml`. Enable it with:

```bash
pre-commit install
pre-commit run --all-files
```

## License

MIT — see [LICENSE](LICENSE).
