qualtrics 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- qualtrics-0.1.1/.gitignore +201 -0
- qualtrics-0.1.1/PKG-INFO +351 -0
- qualtrics-0.1.1/README.md +338 -0
- qualtrics-0.1.1/pyproject.toml +120 -0
- qualtrics-0.1.1/src/qualtrics/__init__.py +18 -0
- qualtrics-0.1.1/src/qualtrics/__main__.py +3 -0
- qualtrics-0.1.1/src/qualtrics/analytics/__init__.py +3 -0
- qualtrics-0.1.1/src/qualtrics/analytics/report.py +134 -0
- qualtrics-0.1.1/src/qualtrics/api/__init__.py +49 -0
- qualtrics-0.1.1/src/qualtrics/api/client.py +168 -0
- qualtrics-0.1.1/src/qualtrics/api/domains/__init__.py +10 -0
- qualtrics-0.1.1/src/qualtrics/api/domains/base.py +11 -0
- qualtrics-0.1.1/src/qualtrics/api/domains/response_exports.py +203 -0
- qualtrics-0.1.1/src/qualtrics/api/domains/survey_definitions.py +31 -0
- qualtrics-0.1.1/src/qualtrics/api/domains/surveys.py +34 -0
- qualtrics-0.1.1/src/qualtrics/api/exceptions.py +13 -0
- qualtrics-0.1.1/src/qualtrics/api/models.py +128 -0
- qualtrics-0.1.1/src/qualtrics/api/settings.py +13 -0
- qualtrics-0.1.1/src/qualtrics/cli/__init__.py +3 -0
- qualtrics-0.1.1/src/qualtrics/cli/api.py +70 -0
- qualtrics-0.1.1/src/qualtrics/cli/app.py +10 -0
- qualtrics-0.1.1/src/qualtrics/cli/build.py +40 -0
- qualtrics-0.1.1/src/qualtrics/cli/report.py +40 -0
- qualtrics-0.1.1/src/qualtrics/models/__init__.py +4 -0
- qualtrics-0.1.1/src/qualtrics/models/entities.py +29 -0
- qualtrics-0.1.1/src/qualtrics/models/entity_set.py +19 -0
- qualtrics-0.1.1/src/qualtrics/parsers/__init__.py +3 -0
- qualtrics-0.1.1/src/qualtrics/parsers/identity.py +52 -0
- qualtrics-0.1.1/src/qualtrics/parsers/paths.py +16 -0
- qualtrics-0.1.1/src/qualtrics/parsers/qsf.py +64 -0
- qualtrics-0.1.1/src/qualtrics/parsers/survey.py +213 -0
- qualtrics-0.1.1/src/qualtrics/py.typed +0 -0
- qualtrics-0.1.1/src/qualtrics/reporting/__init__.py +3 -0
- qualtrics-0.1.1/src/qualtrics/reporting/assets.py +6 -0
- qualtrics-0.1.1/src/qualtrics/reporting/report.py +337 -0
- qualtrics-0.1.1/src/qualtrics/reporting/static/report.css +70 -0
- qualtrics-0.1.1/src/qualtrics/reporting/static/report.js +48 -0
- qualtrics-0.1.1/src/qualtrics/serialization/__init__.py +3 -0
- qualtrics-0.1.1/src/qualtrics/serialization/io.py +61 -0
- qualtrics-0.1.1/src/qualtrics/services/__init__.py +3 -0
- qualtrics-0.1.1/src/qualtrics/version.py +1 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# Created by https://www.toptal.com/developers/gitignore/api/python,venv
|
|
2
|
+
# Edit at https://www.toptal.com/developers/gitignore?templates=python,venv
|
|
3
|
+
|
|
4
|
+
### Python ###
|
|
5
|
+
# Byte-compiled / optimized / DLL files
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
*$py.class
|
|
9
|
+
|
|
10
|
+
# C extensions
|
|
11
|
+
*.so
|
|
12
|
+
|
|
13
|
+
# Distribution / packaging
|
|
14
|
+
.DS_Store
|
|
15
|
+
.Python
|
|
16
|
+
build/
|
|
17
|
+
develop-eggs/
|
|
18
|
+
dist/
|
|
19
|
+
downloads/
|
|
20
|
+
eggs/
|
|
21
|
+
.eggs/
|
|
22
|
+
lib/
|
|
23
|
+
lib64/
|
|
24
|
+
parts/
|
|
25
|
+
sdist/
|
|
26
|
+
var/
|
|
27
|
+
wheels/
|
|
28
|
+
share/python-wheels/
|
|
29
|
+
*.egg-info/
|
|
30
|
+
.installed.cfg
|
|
31
|
+
*.egg
|
|
32
|
+
MANIFEST
|
|
33
|
+
|
|
34
|
+
# PyInstaller
|
|
35
|
+
# Usually these files are written by a python script from a template
|
|
36
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
37
|
+
*.manifest
|
|
38
|
+
*.spec
|
|
39
|
+
|
|
40
|
+
# Installer logs
|
|
41
|
+
pip-log.txt
|
|
42
|
+
pip-delete-this-directory.txt
|
|
43
|
+
|
|
44
|
+
# Unit test / coverage reports
|
|
45
|
+
htmlcov/
|
|
46
|
+
.tox/
|
|
47
|
+
.nox/
|
|
48
|
+
.coverage
|
|
49
|
+
.coverage.*
|
|
50
|
+
.cache
|
|
51
|
+
nosetests.xml
|
|
52
|
+
coverage.xml
|
|
53
|
+
*.cover
|
|
54
|
+
*.py,cover
|
|
55
|
+
.hypothesis/
|
|
56
|
+
.pytest_cache/
|
|
57
|
+
cover/
|
|
58
|
+
reports/
|
|
59
|
+
|
|
60
|
+
# Translations
|
|
61
|
+
*.mo
|
|
62
|
+
*.pot
|
|
63
|
+
|
|
64
|
+
# Django stuff:
|
|
65
|
+
*.log
|
|
66
|
+
local_settings.py
|
|
67
|
+
db.sqlite3
|
|
68
|
+
db.sqlite3-journal
|
|
69
|
+
|
|
70
|
+
# Flask stuff:
|
|
71
|
+
instance/
|
|
72
|
+
.webassets-cache
|
|
73
|
+
|
|
74
|
+
# Scrapy stuff:
|
|
75
|
+
.scrapy
|
|
76
|
+
|
|
77
|
+
# Sphinx documentation
|
|
78
|
+
docs/_build/
|
|
79
|
+
|
|
80
|
+
# PyBuilder
|
|
81
|
+
.pybuilder/
|
|
82
|
+
target/
|
|
83
|
+
|
|
84
|
+
# Jupyter Notebook
|
|
85
|
+
.ipynb_checkpoints
|
|
86
|
+
|
|
87
|
+
# IPython
|
|
88
|
+
profile_default/
|
|
89
|
+
ipython_config.py
|
|
90
|
+
|
|
91
|
+
# pyenv
|
|
92
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
93
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
94
|
+
# .python-version
|
|
95
|
+
|
|
96
|
+
# pipenv
|
|
97
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
98
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
99
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
100
|
+
# install all needed dependencies.
|
|
101
|
+
#Pipfile.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
#poetry.lock
|
|
109
|
+
|
|
110
|
+
# pdm
|
|
111
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
112
|
+
#pdm.lock
|
|
113
|
+
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
|
|
114
|
+
# in version control.
|
|
115
|
+
# https://pdm.fming.dev/#use-with-ide
|
|
116
|
+
.pdm.toml
|
|
117
|
+
|
|
118
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
119
|
+
__pypackages__/
|
|
120
|
+
|
|
121
|
+
# Celery stuff
|
|
122
|
+
celerybeat-schedule
|
|
123
|
+
celerybeat.pid
|
|
124
|
+
|
|
125
|
+
# SageMath parsed files
|
|
126
|
+
*.sage.py
|
|
127
|
+
|
|
128
|
+
# Environments
|
|
129
|
+
*.env
|
|
130
|
+
.env
|
|
131
|
+
.venv
|
|
132
|
+
env/
|
|
133
|
+
venv/
|
|
134
|
+
ENV/
|
|
135
|
+
env.bak/
|
|
136
|
+
venv.bak/
|
|
137
|
+
|
|
138
|
+
# Spyder project settings
|
|
139
|
+
.spyderproject
|
|
140
|
+
.spyproject
|
|
141
|
+
|
|
142
|
+
# Rope project settings
|
|
143
|
+
.ropeproject
|
|
144
|
+
|
|
145
|
+
# mkdocs documentation
|
|
146
|
+
/site
|
|
147
|
+
|
|
148
|
+
# mypy
|
|
149
|
+
.mypy_cache/
|
|
150
|
+
.dmypy.json
|
|
151
|
+
dmypy.json
|
|
152
|
+
|
|
153
|
+
# Pyre type checker
|
|
154
|
+
.pyre/
|
|
155
|
+
|
|
156
|
+
# pytype static type analyzer
|
|
157
|
+
.pytype/
|
|
158
|
+
|
|
159
|
+
# Cython debug symbols
|
|
160
|
+
cython_debug/
|
|
161
|
+
|
|
162
|
+
# PyCharm
|
|
163
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
164
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
165
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
166
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
167
|
+
#.idea/
|
|
168
|
+
|
|
169
|
+
### Python Patch ###
|
|
170
|
+
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
|
|
171
|
+
poetry.toml
|
|
172
|
+
|
|
173
|
+
# ruff
|
|
174
|
+
.ruff_cache/
|
|
175
|
+
|
|
176
|
+
# LSP config files
|
|
177
|
+
pyrightconfig.json
|
|
178
|
+
|
|
179
|
+
### venv ###
|
|
180
|
+
# Virtualenv
|
|
181
|
+
# http://iamzed.com/2009/05/07/a-primer-on-virtualenv/
|
|
182
|
+
[Bb]in
|
|
183
|
+
[Ii]nclude
|
|
184
|
+
[Ll]ib
|
|
185
|
+
[Ll]ib64
|
|
186
|
+
[Ll]ocal
|
|
187
|
+
[Ss]cripts
|
|
188
|
+
pyvenv.cfg
|
|
189
|
+
pip-selfcheck.json
|
|
190
|
+
|
|
191
|
+
# Visual Studio Code #
|
|
192
|
+
.vscode
|
|
193
|
+
!.vscode/settings.json
|
|
194
|
+
!.vscode/tasks.json
|
|
195
|
+
!.vscode/launch.json
|
|
196
|
+
!.vscode/extensions.json
|
|
197
|
+
.history
|
|
198
|
+
|
|
199
|
+
# Repository maintenance scripts are source files, not virtualenv scripts.
|
|
200
|
+
!/scripts/
|
|
201
|
+
!/scripts/*.py
|
qualtrics-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: qualtrics
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: A typed Qualtrics SDK and offline survey data toolkit
|
|
5
|
+
Requires-Python: >=3.11
|
|
6
|
+
Requires-Dist: httpx<1,>=0.27
|
|
7
|
+
Requires-Dist: pydantic-settings<3,>=2.4
|
|
8
|
+
Requires-Dist: pydantic<3,>=2.8
|
|
9
|
+
Requires-Dist: typer<1,>=0.12
|
|
10
|
+
Provides-Extra: parquet
|
|
11
|
+
Requires-Dist: pyarrow>=17; extra == 'parquet'
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
# Qualtrics
|
|
15
|
+
|
|
16
|
+
`qualtrics` is a Python library and Typer CLI for working with
|
|
17
|
+
Qualtrics surveys end to end:
|
|
18
|
+
|
|
19
|
+
- list and update surveys through Qualtrics API v3;
|
|
20
|
+
- import responses and download response exports;
|
|
21
|
+
- parse one or many Qualtrics CSV exports, with or without QSF metadata;
|
|
22
|
+
- preserve survey, question, concrete field, block, and loop identities;
|
|
23
|
+
- build survey-local entities and cross-survey canonical catalogs;
|
|
24
|
+
- write JSON, CSV, or Parquet datasets;
|
|
25
|
+
- calculate question-type-aware analytics and data-quality signals; and
|
|
26
|
+
- create a self-contained, interactive HTML report.
|
|
27
|
+
|
|
28
|
+
It is useful for conventional surveys and for administrative data-intake
|
|
29
|
+
workflows where different people answer different sections—for example
|
|
30
|
+
institutional reporting, accreditation, compliance, annual collections, grant
|
|
31
|
+
reporting, and multi-stakeholder intake forms.
|
|
32
|
+
|
|
33
|
+
## Why CSV and QSF are both useful
|
|
34
|
+
|
|
35
|
+
A Qualtrics response CSV normally begins with three header rows:
|
|
36
|
+
|
|
37
|
+
1. exported field name, such as `4_cat_train`;
|
|
38
|
+
2. question and field text;
|
|
39
|
+
3. metadata such as `{"ImportId":"4_QID30"}`.
|
|
40
|
+
|
|
41
|
+
Multi-field, matrix, form, looped, and text-entry questions can create several
|
|
42
|
+
CSV fields for one logical survey question. The toolkit never identifies a
|
|
43
|
+
concrete answer using stripped question text. It retains the full field name,
|
|
44
|
+
ImportId, suffix, and column index.
|
|
45
|
+
|
|
46
|
+
QSF metadata is optional but strongly recommended. It supplies definitive
|
|
47
|
+
question types, complete question text, choices, survey blocks, and loop
|
|
48
|
+
configuration. Without QSF, the toolkit infers what it safely can from the CSV.
|
|
49
|
+
When `--qsf` is omitted, the toolkit automatically uses a `.qsf` file beside
|
|
50
|
+
the CSV when both files have the same filename stem. Extension matching is
|
|
51
|
+
case-insensitive, so `annual-survey.csv` can match `annual-survey.QSF`.
|
|
52
|
+
|
|
53
|
+
For a manual export in Qualtrics:
|
|
54
|
+
|
|
55
|
+
1. Open **Data & Analysis → Export & Import → Export Data**.
|
|
56
|
+
2. Choose CSV and, for readable reports, enable choice text rather than numeric
|
|
57
|
+
codes.
|
|
58
|
+
3. Download the QSF from **Survey → Tools → Import/Export → Export Survey**.
|
|
59
|
+
4. Give matching CSV and QSF files the same sortable base name.
|
|
60
|
+
|
|
61
|
+
## Installation with uv
|
|
62
|
+
|
|
63
|
+
From this repository:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
uv sync
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Run the CLI without installing it globally:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
uv run qualtrics --help
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Parquet support:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
uv sync --extra parquet
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Build entity datasets
|
|
82
|
+
|
|
83
|
+
One survey:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
uv run qualtrics build \
|
|
87
|
+
survey.csv --qsf survey.qsf --output entities --format json
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
With matching files such as `survey.csv` and `survey.qsf`, `--qsf` is optional:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
uv run qualtrics build \
|
|
94
|
+
survey.csv --output entities --format json
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Multiple surveys:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
uv run qualtrics build \
|
|
101
|
+
survey-v1.csv survey-v2.csv \
|
|
102
|
+
--qsf survey-v1.qsf --qsf survey-v2.qsf \
|
|
103
|
+
--output entities --format parquet
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Directories are supported too. CSV and QSF directory contents are sorted by
|
|
107
|
+
filename and paired in that order:
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
uv run qualtrics build \
|
|
111
|
+
./exports/csv --qsf ./exports/qsf --output entities
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The output contains:
|
|
115
|
+
|
|
116
|
+
| Entity | Identity and purpose |
|
|
117
|
+
| --- | --- |
|
|
118
|
+
| `surveys` | Survey/version metadata |
|
|
119
|
+
| `sections` | Survey-local Qualtrics blocks and their display order |
|
|
120
|
+
| `question_catalog` | Canonical logical questions shared across surveys |
|
|
121
|
+
| `question_field_catalog` | Canonical fields shared across surveys |
|
|
122
|
+
| `questions` | Survey-local question occurrences, types, blocks, and order |
|
|
123
|
+
| `question_fields` | Concrete CSV columns and ImportIds |
|
|
124
|
+
| `answer_options` | Defined respondent options—not Meta Info fields |
|
|
125
|
+
| `responses` | Response metadata |
|
|
126
|
+
| `response_answers` | Answers linked through survey, response, question, and field |
|
|
127
|
+
|
|
128
|
+
The central answer relationship is:
|
|
129
|
+
|
|
130
|
+
```text
|
|
131
|
+
response_answer
|
|
132
|
+
→ (survey_id, response_id)
|
|
133
|
+
→ (survey_id, question_id, field_id)
|
|
134
|
+
→ question_catalog_id / question_field_catalog_id
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Entity records describe survey data only. Pipeline lineage such as ingestion
|
|
138
|
+
run IDs belongs in the surrounding platform manifest or control tables and is
|
|
139
|
+
therefore not added by the parser.
|
|
140
|
+
|
|
141
|
+
`parse_survey` also accepts wildcard paths. This is useful for run-oriented
|
|
142
|
+
lakehouse layouts where each survey has its own folder:
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
from qualtrics import parse_survey
|
|
146
|
+
|
|
147
|
+
entities = parse_survey("/lakehouse/default/Files/qualtrics/run-1/*/*.csv")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Each CSV is paired automatically with a same-stem `.qsf` or `.json` definition
|
|
151
|
+
in its directory. Prefer a single-level pattern like `*/*.csv`; recursive
|
|
152
|
+
patterns may also select translated CSV files stored below `translations/`.
|
|
153
|
+
|
|
154
|
+
## Generate an HTML report
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
uv run qualtrics report \
|
|
158
|
+
--folder entities --output report.html
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The report is one portable HTML file with embedded styling and behavior. It
|
|
162
|
+
includes survey selection, response and question filters, blocks, metadata,
|
|
163
|
+
coverage, question-type-aware analytics, and per-survey data-quality findings.
|
|
164
|
+
All source values are HTML-escaped.
|
|
165
|
+
|
|
166
|
+
## Qualtrics API SDK
|
|
167
|
+
|
|
168
|
+
Set credentials without putting the token in shell history:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
export QUALTRICS_API_TOKEN="..."
|
|
172
|
+
export QUALTRICS_DATA_CENTER="ca1"
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Your data-center identifier is the first part of the Qualtrics host used by
|
|
176
|
+
your account. You may instead set `QUALTRICS_BASE_URL` for a custom API base.
|
|
177
|
+
Explicit constructor arguments override matching environment variables:
|
|
178
|
+
|
|
179
|
+
```python
|
|
180
|
+
from qualtrics import QualtricsClient
|
|
181
|
+
|
|
182
|
+
client = QualtricsClient() # reads QUALTRICS_API_TOKEN and connection settings
|
|
183
|
+
client = QualtricsClient(api_token="...", data_center="ca1")
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
List surveys:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
uv run qualtrics api surveys
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Export labeled CSV responses and name the ZIP after the survey ID:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
uv run qualtrics api export SV_123 --output exports --labels \
|
|
196
|
+
--naming survey_id
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Import a UTF-8 CSV response file and wait for processing:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
uv run qualtrics api import SV_123 responses.csv
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Naming strategies are `qualtrics`, `survey_id`, `survey_name`, and `custom`.
|
|
206
|
+
For custom naming, add `--filename my-export`. An explicit output file path
|
|
207
|
+
always takes precedence.
|
|
208
|
+
|
|
209
|
+
Python usage:
|
|
210
|
+
|
|
211
|
+
```python
|
|
212
|
+
from pathlib import Path
|
|
213
|
+
|
|
214
|
+
from qualtrics import QualtricsClient
|
|
215
|
+
from qualtrics.api import FilenameStrategy, ResponseExportRequest
|
|
216
|
+
|
|
217
|
+
# With no arguments, credentials are read from QUALTRICS_* variables.
|
|
218
|
+
with QualtricsClient() as client:
|
|
219
|
+
surveys = list(client.surveys.iter())
|
|
220
|
+
result = client.responses.export(
|
|
221
|
+
surveys[0].id,
|
|
222
|
+
Path("exports"),
|
|
223
|
+
options=ResponseExportRequest(format="csv", use_labels=True),
|
|
224
|
+
naming=FilenameStrategy.SURVEY_NAME,
|
|
225
|
+
survey_name=surveys[0].name,
|
|
226
|
+
)
|
|
227
|
+
print(result.path)
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
The context manager is recommended because it closes the underlying HTTPX
|
|
231
|
+
connection pool deterministically. Long-lived applications can instead create
|
|
232
|
+
one client, reuse it, and call `client.close()` during application shutdown.
|
|
233
|
+
|
|
234
|
+
The export workflow starts an asynchronous job, polls its `progressId`, obtains
|
|
235
|
+
the resulting `fileId`, and downloads the binary file. The low-level
|
|
236
|
+
`client.request(...)` method provides access to API v3 endpoints not yet covered
|
|
237
|
+
by a typed resource method.
|
|
238
|
+
|
|
239
|
+
The API client uses domain resources rather than placing every endpoint on the
|
|
240
|
+
root client:
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
with QualtricsClient() as client:
|
|
244
|
+
survey = client.surveys.get("SV_123")
|
|
245
|
+
client.surveys.update("SV_123", {"name": "Annual survey"})
|
|
246
|
+
filters = list(client.responses.iter_filters("SV_123"))
|
|
247
|
+
job = client.responses.start("SV_123")
|
|
248
|
+
progress = client.responses.wait("SV_123", job.progress_id)
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
`client.responses` covers local-file and hosted-file imports, import progress,
|
|
252
|
+
saved filters, export creation/progress, and export download. The older
|
|
253
|
+
`client.response_exports` attribute remains as an alias. Survey structure
|
|
254
|
+
operations such as definitions and metadata are intentionally exposed through
|
|
255
|
+
`client.survey_definitions`, separate from the `/surveys` CRUD resource.
|
|
256
|
+
|
|
257
|
+
The root client owns authentication, error handling, and HTTP transport. Domain
|
|
258
|
+
packages own endpoint paths and workflows. Compatibility delegates such as
|
|
259
|
+
`client.iter_surveys()` remain available for existing callers.
|
|
260
|
+
|
|
261
|
+
Qualtrics currently documents CSV, TSV, JSON, NDJSON, XML, and SPSS response
|
|
262
|
+
exports. Large exports should use filters, date ranges, selected questions, or
|
|
263
|
+
continuation tokens where appropriate.
|
|
264
|
+
|
|
265
|
+
## Python API
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
from qualtrics import parse_surveys, render_report, write_entities
|
|
269
|
+
|
|
270
|
+
entities = parse_surveys(
|
|
271
|
+
["survey-v1.csv", "survey-v2.csv"],
|
|
272
|
+
["survey-v1.qsf", "survey-v2.qsf"],
|
|
273
|
+
)
|
|
274
|
+
write_entities(entities, "entities", format="json")
|
|
275
|
+
render_report(entities, "report.html")
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
## Source layout
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
src/qualtrics/
|
|
282
|
+
├── api/ # HTTP client, API models, and domain resources
|
|
283
|
+
├── analytics/ # Coverage and data-quality calculations
|
|
284
|
+
├── cli/ # Small Typer command modules
|
|
285
|
+
├── models/ # EntitySet and entity collection operations
|
|
286
|
+
├── parsers/ # CSV, QSF, identity, and path parsing
|
|
287
|
+
├── reporting/ # HTML renderer and bundled CSS/JavaScript
|
|
288
|
+
├── serialization/ # CSV, JSON, and Parquet entity I/O
|
|
289
|
+
└── services/ # Cross-domain application services
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
The API and offline data tooling are equal package capabilities. The `api/`
|
|
293
|
+
domain owns HTTP resources and API models; parsing, analytics, reporting, and
|
|
294
|
+
serialization remain independent and never require network credentials.
|
|
295
|
+
The package contains no catch-all core module: each public operation is exported
|
|
296
|
+
from the domain that implements it.
|
|
297
|
+
|
|
298
|
+
The distribution, CLI, and Python import are all named `qualtrics`.
|
|
299
|
+
|
|
300
|
+
## Development
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
uv sync --group dev --group test --extra parquet
|
|
304
|
+
uv run pre-commit install --hook-type pre-commit --hook-type pre-push
|
|
305
|
+
uv run poe check
|
|
306
|
+
uv run poe build
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
Run every commit hook manually with `uv run poe pre-commit`. Ruff and `ty` run
|
|
310
|
+
before commits; the complete pytest suite additionally runs before pushes.
|
|
311
|
+
|
|
312
|
+
## Releases
|
|
313
|
+
|
|
314
|
+
Run the **Prepare Release** workflow from GitHub Actions and choose a patch,
|
|
315
|
+
minor, or major bump. The workflow updates `pyproject.toml` and `uv.lock`,
|
|
316
|
+
prepends a dated section to [`release-notes.md`](release-notes.md), validates the
|
|
317
|
+
package, and opens a release pull request. After merging it, publish a GitHub
|
|
318
|
+
release using the matching `vX.Y.Z` tag; the **Publish** workflow then verifies
|
|
319
|
+
the tag, builds and attests the distributions, and publishes them through the
|
|
320
|
+
PyPI `pypi` environment.
|
|
321
|
+
|
|
322
|
+
## Examples
|
|
323
|
+
|
|
324
|
+
Runnable examples live in [`examples/`](examples/):
|
|
325
|
+
|
|
326
|
+
```bash
|
|
327
|
+
# Parse one CSV; a matching QSF is discovered automatically.
|
|
328
|
+
uv run python examples/parse_survey.py survey.csv
|
|
329
|
+
|
|
330
|
+
# Parse all CSV files in a directory into one multi-survey report.
|
|
331
|
+
uv run python examples/parse_multiple_surveys.py exports
|
|
332
|
+
|
|
333
|
+
# List surveys, or add --survey-id SV_123 to export responses.
|
|
334
|
+
uv run python examples/api_list_and_export.py
|
|
335
|
+
|
|
336
|
+
# Import responses into an existing survey.
|
|
337
|
+
uv run python examples/api_import_responses.py \
|
|
338
|
+
SV_123 responses.csv
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
API examples read `QUALTRICS_API_TOKEN` and `QUALTRICS_DATA_CENTER` from the
|
|
342
|
+
environment. Importing responses changes data in the target survey, so verify
|
|
343
|
+
the survey ID before running that example.
|
|
344
|
+
|
|
345
|
+
## Acknowledgements
|
|
346
|
+
|
|
347
|
+
The usage guidance and administrative-survey examples were informed by the
|
|
348
|
+
[Qualtrics Report Generator](https://github.com/hihipy/qualtrics-report-generator)
|
|
349
|
+
README. API behavior should be checked against the
|
|
350
|
+
[official Qualtrics API documentation](https://api.qualtrics.com/) for the
|
|
351
|
+
features enabled on your account.
|