Metadata-Version: 2.5
Name: qualtrics
Version: 0.1.2
Summary: A typed Qualtrics SDK and offline survey data toolkit
Project-URL: Homepage, https://github.com/Luanee/qualtrics
Project-URL: Repository, https://github.com/Luanee/qualtrics
Project-URL: Issues, https://github.com/Luanee/qualtrics/issues
Project-URL: Changelog, https://github.com/Luanee/qualtrics/blob/main/release-notes.md
Author-email: Pit Nahrstedt <pit.nahrstedt@outlook.live>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Framework :: Pydantic
Classifier: Framework :: Pydantic :: 2
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Internet
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Utilities
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: httpx<1,>=0.27
Requires-Dist: pydantic-settings<3,>=2.4
Requires-Dist: pydantic<3,>=2.8
Requires-Dist: typer<1,>=0.12
Provides-Extra: parquet
Requires-Dist: pyarrow>=17; extra == 'parquet'
Description-Content-Type: text/markdown

# Qualtrics

[![Python](https://img.shields.io/pypi/pyversions/qualtrics?logo=python&logoColor=white)](https://pypi.org/project/qualtrics/)
[![Ruff](https://img.shields.io/badge/code%20style-Ruff-D7FF64?logo=ruff&logoColor=261230)](https://docs.astral.sh/ruff/)
[![Coverage](https://img.shields.io/badge/coverage-%E2%89%A575%25-brightgreen)](#development)
[![PyPI](https://img.shields.io/pypi/v/qualtrics?logo=pypi&logoColor=white)](https://pypi.org/project/qualtrics/)
[![Tests](https://img.shields.io/github/actions/workflow/status/Luanee/qualtrics/ci.yml?branch=main&label=tests&logo=github)](https://github.com/Luanee/qualtrics/actions/workflows/ci.yml)

`qualtrics` is a typed Python SDK and Typer CLI for the Qualtrics API and
offline survey data. It can:

- list and update surveys through Qualtrics API v3;
- import and export survey responses;
- parse CSV or response-export ZIP files, with or without survey definitions;
- preserve questions, concrete fields, answer options, and survey blocks;
- write normalized JSON, CSV, or Parquet entities; and
- generate an interactive HTML report with data-quality and question analytics.

## Install

```bash
uv add qualtrics
```

Install Parquet support when needed:

```bash
uv add "qualtrics[parquet]"
```

For development from this repository:

```bash
uv sync --all-groups --extra parquet
```

## Configure the API

Create a `.env` file or export the same variables in your shell:

```dotenv
QUALTRICS_API_TOKEN=your-token
QUALTRICS_DATA_CENTER=ca1
```

Use `QUALTRICS_BASE_URL` instead of `QUALTRICS_DATA_CENTER` when your account
requires a custom API base URL. Explicit `QualtricsClient(...)` arguments take
precedence over environment settings.

## Export, parse, and report

The complete example accepts a survey ID, downloads its definition and
responses, extracts the original CSV, creates Parquet entities, and renders an
HTML report:

```bash
uv run python examples/export_parse_and_report.py SV_123
```

It creates:

```text
data/
└── SV_123/
    ├── definition.qsf
    ├── export.zip
    ├── responses.csv
    ├── report.html
    └── entities/
        ├── surveys.parquet
        ├── sections.parquet
        ├── questions.parquet
        ├── question_fields.parquet
        ├── question_catalog.parquet
        ├── question_field_catalog.parquet
        ├── answer_options.parquet
        ├── responses.parquet
        └── response_answers.parquet
```

Parquet is the default. Select another entity format with `--format json` or
`--format csv`; export coded values with `--codes`.

## Parse existing exports

Parse a CSV and matching survey definition:

```bash
uv run qualtrics build responses.csv \
  --qsf definition.qsf \
  --output entities \
  --format parquet
```

Response-export ZIP files can be parsed directly:

```bash
uv run qualtrics build export.zip \
  --qsf definition.qsf \
  --output entities \
  --format parquet
```

When the response file and definition share a filename stem, the definition is
discovered automatically. For example, `SV_123.zip` matches `SV_123.qsf`.

Python usage:

```python
from qualtrics import parse_survey, render_report, write_entities

entities = parse_survey("responses.csv", "definition.qsf")
write_entities(entities, "entities", format="parquet")
render_report(entities, "report.html")
```

Wildcards support multiple surveys and lakehouse-style layouts:

```python
entities = parse_survey("/lakehouse/default/Files/qualtrics/run-1/*/*.csv")
```

## Why the survey definition matters

A Qualtrics CSV commonly starts with three header rows:

1. the exported field name;
2. the question and field text; and
3. metadata such as `{"ImportId":"QID30_4_TEXT"}`.

One logical question can produce many concrete CSV fields for choices, matrix
rows, loops, or text entries. The parser retains the complete field name,
ImportId, suffix, and column index instead of collapsing fields by normalized
question text.

A QSF or API survey definition is optional but recommended. It supplies the
survey name, question types, choices, blocks, and other metadata that cannot be
reliably reconstructed from response headers alone.

## Entity model

| Entity | Purpose |
| --- | --- |
| `surveys` | Survey identity and metadata |
| `sections` | Survey blocks and display order |
| `questions` | Survey-local questions, types, and block membership |
| `question_fields` | Concrete CSV fields and ImportIds |
| `answer_options` | Options defined for response questions |
| `responses` | Respondent and response metadata |
| `response_answers` | Values linked to responses, questions, and fields |
| `question_catalog` | Canonical questions shared across surveys |
| `question_field_catalog` | Canonical fields shared across surveys |

The primary relationship is:

```text
response_answer
  → (survey_id, response_id)
  → (survey_id, question_id, field_id)
  → question_catalog_id / question_field_catalog_id
```

Pipeline lineage such as an ingestion run ID belongs in the surrounding data
platform, not in the parser entities.

## SDK and CLI

```python
from qualtrics import QualtricsClient

with QualtricsClient() as client:
    for survey in client.surveys.iter():
        print(survey.id, survey.name)

    definition = client.survey_definitions.get("SV_123")
```

Common CLI commands:

```bash
uv run qualtrics api surveys
uv run qualtrics api export SV_123 --output exports --labels
uv run qualtrics api import SV_123 responses.csv
uv run qualtrics report --folder entities --output report.html
```

`client.surveys` covers survey CRUD. `client.survey_definitions` handles survey
structure, while `client.responses` handles imports, exports, progress, and
saved response filters.

## Development

```bash
uv sync --all-groups --extra parquet
uv run pre-commit install --hook-type pre-commit --hook-type pre-push
uv run poe check
uv run poe build
```

CI tests Python 3.11–3.14. Ruff checks formatting and linting, `ty` checks
types, and pytest enforces at least 75% branch-aware coverage.

Releases are prepared through the **Prepare Release** GitHub workflow. See
[`release-notes.md`](release-notes.md) for version history and
[`examples/`](examples/) for runnable API and parsing examples.

## Acknowledgements

The workflow guidance was informed by the
[Qualtrics Report Generator](https://github.com/hihipy/qualtrics-report-generator).
Consult the [official Qualtrics API documentation](https://api.qualtrics.com/)
for features enabled on your account.
