siamang 0.5.0__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.
- siamang-0.5.0/CHANGELOG.md +55 -0
- siamang-0.5.0/LICENSE +21 -0
- siamang-0.5.0/MANIFEST.in +13 -0
- siamang-0.5.0/PKG-INFO +335 -0
- siamang-0.5.0/README.md +282 -0
- siamang-0.5.0/docs/concepts.md +247 -0
- siamang-0.5.0/docs/cookbook.md +351 -0
- siamang-0.5.0/docs/getting-started.md +112 -0
- siamang-0.5.0/docs/index.md +104 -0
- siamang-0.5.0/docs/reference/cli.md +193 -0
- siamang-0.5.0/docs/reference/core.md +491 -0
- siamang-0.5.0/docs/reference/data.md +187 -0
- siamang-0.5.0/docs/reference/deploy.md +494 -0
- siamang-0.5.0/docs/reference/frontend.md +278 -0
- siamang-0.5.0/docs/reference/io.md +155 -0
- siamang-0.5.0/docs/reference/reporting.md +318 -0
- siamang-0.5.0/pyproject.toml +131 -0
- siamang-0.5.0/setup.cfg +4 -0
- siamang-0.5.0/siamang/__init__.py +124 -0
- siamang-0.5.0/siamang/__main__.py +6 -0
- siamang-0.5.0/siamang/cli/__init__.py +5 -0
- siamang-0.5.0/siamang/cli/__main__.py +6 -0
- siamang-0.5.0/siamang/cli/deploy.py +54 -0
- siamang-0.5.0/siamang/cli/entry.py +91 -0
- siamang-0.5.0/siamang/cli/init.py +63 -0
- siamang-0.5.0/siamang/cli/loader.py +34 -0
- siamang-0.5.0/siamang/cli/preview.py +73 -0
- siamang-0.5.0/siamang/cli/validate.py +32 -0
- siamang-0.5.0/siamang/config/__init__.py +14 -0
- siamang-0.5.0/siamang/config/loader.py +193 -0
- siamang-0.5.0/siamang/config/secrets.py +29 -0
- siamang-0.5.0/siamang/core/__init__.py +59 -0
- siamang-0.5.0/siamang/core/block.py +26 -0
- siamang-0.5.0/siamang/core/expression.py +235 -0
- siamang-0.5.0/siamang/core/filter_rule.py +18 -0
- siamang-0.5.0/siamang/core/media.py +93 -0
- siamang-0.5.0/siamang/core/option.py +57 -0
- siamang-0.5.0/siamang/core/page.py +30 -0
- siamang-0.5.0/siamang/core/question.py +254 -0
- siamang-0.5.0/siamang/core/questionnaire.py +527 -0
- siamang-0.5.0/siamang/core/quota.py +17 -0
- siamang-0.5.0/siamang/core/script.py +174 -0
- siamang-0.5.0/siamang/core/serialization.py +92 -0
- siamang-0.5.0/siamang/core/variable.py +497 -0
- siamang-0.5.0/siamang/data/__init__.py +6 -0
- siamang-0.5.0/siamang/data/analysis.py +285 -0
- siamang-0.5.0/siamang/data/processing.py +20 -0
- siamang-0.5.0/siamang/data/survey_data.py +404 -0
- siamang-0.5.0/siamang/data/tables.py +114 -0
- siamang-0.5.0/siamang/deploy/__init__.py +24 -0
- siamang-0.5.0/siamang/deploy/backend_config.py +23 -0
- siamang-0.5.0/siamang/deploy/backends/gsheets.py +416 -0
- siamang-0.5.0/siamang/deploy/backends/local.py +169 -0
- siamang-0.5.0/siamang/deploy/backends/supabase.py +501 -0
- siamang-0.5.0/siamang/deploy/base.py +45 -0
- siamang-0.5.0/siamang/deploy/frontends/local.py +241 -0
- siamang-0.5.0/siamang/deploy/frontends/netlify.py +274 -0
- siamang-0.5.0/siamang/deploy/frontends/vercel.py +196 -0
- siamang-0.5.0/siamang/deploy/pipeline.py +79 -0
- siamang-0.5.0/siamang/deploy/registry.py +69 -0
- siamang-0.5.0/siamang/deploy/result.py +36 -0
- siamang-0.5.0/siamang/frontend/__init__.py +66 -0
- siamang-0.5.0/siamang/frontend/builder.py +110 -0
- siamang-0.5.0/siamang/frontend/bundle.py +97 -0
- siamang-0.5.0/siamang/frontend/client/__init__.py +14 -0
- siamang-0.5.0/siamang/frontend/client/base.py +34 -0
- siamang-0.5.0/siamang/frontend/client/gsheets.py +98 -0
- siamang-0.5.0/siamang/frontend/client/local.py +51 -0
- siamang-0.5.0/siamang/frontend/client/supabase.py +66 -0
- siamang-0.5.0/siamang/frontend/compiler/__init__.py +12 -0
- siamang-0.5.0/siamang/frontend/compiler/logic.py +43 -0
- siamang-0.5.0/siamang/frontend/compiler/quota.py +22 -0
- siamang-0.5.0/siamang/frontend/compiler/react.py +466 -0
- siamang-0.5.0/siamang/frontend/compiler/schema.py +116 -0
- siamang-0.5.0/siamang/frontend/constants.py +26 -0
- siamang-0.5.0/siamang/frontend/runtime/__init__.py +7 -0
- siamang-0.5.0/siamang/frontend/runtime/base.py +61 -0
- siamang-0.5.0/siamang/frontend/runtime/react.py +207 -0
- siamang-0.5.0/siamang/frontend/runtime/surveyjs.py +142 -0
- siamang-0.5.0/siamang/frontend/schema.py +71 -0
- siamang-0.5.0/siamang/frontend/templates/closed.html.tpl +16 -0
- siamang-0.5.0/siamang/frontend/templates/index.html.tpl +101 -0
- siamang-0.5.0/siamang/frontend/templates/react/__init__.py +0 -0
- siamang-0.5.0/siamang/frontend/templates/react/app.jsx +712 -0
- siamang-0.5.0/siamang/frontend/templates/react/closed.html.tpl +18 -0
- siamang-0.5.0/siamang/frontend/templates/react/dist/bundle.js +1 -0
- siamang-0.5.0/siamang/frontend/templates/react/hooks.jsx +263 -0
- siamang-0.5.0/siamang/frontend/templates/react/index.html.tpl +39 -0
- siamang-0.5.0/siamang/frontend/templates/react/questions.jsx +785 -0
- siamang-0.5.0/siamang/frontend/templates/react/store.jsx +130 -0
- siamang-0.5.0/siamang/frontend/templates/react/style.css.tpl +1868 -0
- siamang-0.5.0/siamang/frontend/templates/react/vendor/__init__.py +0 -0
- siamang-0.5.0/siamang/frontend/templates/react/vendor/react-dom.production.min.js +267 -0
- siamang-0.5.0/siamang/frontend/templates/react/vendor/react.production.min.js +31 -0
- siamang-0.5.0/siamang/frontend/templates/react/visibility.jsx +164 -0
- siamang-0.5.0/siamang/frontend/theme/__init__.py +7 -0
- siamang-0.5.0/siamang/frontend/theme/css.py +483 -0
- siamang-0.5.0/siamang/frontend/theme/presets.py +98 -0
- siamang-0.5.0/siamang/frontend/theme/ui_config.py +205 -0
- siamang-0.5.0/siamang/io/__init__.py +26 -0
- siamang-0.5.0/siamang/io/csv.py +22 -0
- siamang-0.5.0/siamang/io/dictionary.py +26 -0
- siamang-0.5.0/siamang/io/excel.py +22 -0
- siamang-0.5.0/siamang/io/r.py +77 -0
- siamang-0.5.0/siamang/io/reader.py +26 -0
- siamang-0.5.0/siamang/io/spss.py +155 -0
- siamang-0.5.0/siamang/io/stata.py +111 -0
- siamang-0.5.0/siamang/local_simulator.py +216 -0
- siamang-0.5.0/siamang/py.typed +0 -0
- siamang-0.5.0/siamang/reporting/__init__.py +22 -0
- siamang-0.5.0/siamang/reporting/accessors.py +250 -0
- siamang-0.5.0/siamang/reporting/charts.py +473 -0
- siamang-0.5.0/siamang/reporting/tables.py +373 -0
- siamang-0.5.0/siamang.egg-info/PKG-INFO +335 -0
- siamang-0.5.0/siamang.egg-info/SOURCES.txt +119 -0
- siamang-0.5.0/siamang.egg-info/dependency_links.txt +1 -0
- siamang-0.5.0/siamang.egg-info/entry_points.txt +12 -0
- siamang-0.5.0/siamang.egg-info/requires.txt +37 -0
- siamang-0.5.0/siamang.egg-info/top_level.txt +1 -0
- siamang-0.5.0/tests/test_adapters.py +360 -0
- siamang-0.5.0/tests/test_reporting.py +183 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.5.0] — 2026-05-28
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Theming system**: `UIConfig` with `font_preset` (classic, modern, humanist),
|
|
13
|
+
`accent_color`, and CSS custom properties for full visual customization.
|
|
14
|
+
- **"Other (specify)"** option for `SingleChoice` and `MultiChoice` questions
|
|
15
|
+
via `other_specify=True`.
|
|
16
|
+
- **Answers store**: lightweight reactive store (`useSyncExternalStore`) replacing
|
|
17
|
+
top-level `useState` — eliminates full-tree re-renders on every keystroke.
|
|
18
|
+
- **Compiled visibility**: `show_if`/`hide_if` conditions compiled to JS functions
|
|
19
|
+
at load time (no more per-render AST interpretation).
|
|
20
|
+
- **Hooks decomposition**: `useSurveyNav`, `useSubmission`, `useAutosave`,
|
|
21
|
+
`useLifecycleScripts`, `useKeyboardShortcuts`, `useTheme`.
|
|
22
|
+
- Supabase backend now uses a single shared `responses` table with `survey_id`
|
|
23
|
+
column (consistent with local SQLite backend).
|
|
24
|
+
- Environment variable naming: `SIAMANG_SUPABASE_*` with backward-compatible
|
|
25
|
+
fallback to legacy `SURVLIB_SUPABASE_*`.
|
|
26
|
+
- Script factory functions now use `json.dumps()` for parameter escaping
|
|
27
|
+
(prevents injection from special characters in IDs/messages).
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- Development status set to **Beta** (honest reflection of current test coverage).
|
|
32
|
+
- Slider component: adaptive tick rendering (≤20 steps → labeled ticks,
|
|
33
|
+
>20 steps → end-labels only). Fixes the "wall of numbers" bug.
|
|
34
|
+
- Frontend JS globals renamed: `window.SIAMANG_ENV` / `window.SIAMANG_TRANSPORTS`
|
|
35
|
+
(runtime falls back to legacy `SURVLIB_*` names for backward compatibility).
|
|
36
|
+
|
|
37
|
+
### Fixed
|
|
38
|
+
|
|
39
|
+
- Supabase backend/frontend mismatch: frontend now POSTs `{survey_id, data}`
|
|
40
|
+
matching the shared table schema (previously sent `{survey_id, payload}` to
|
|
41
|
+
a per-survey table that didn't have a `survey_id` column).
|
|
42
|
+
- Slider rendering bug: no longer outputs 61 `<option>` elements for range 0–60.
|
|
43
|
+
|
|
44
|
+
### Removed
|
|
45
|
+
|
|
46
|
+
- Per-survey table creation (`responses_{survey_id}`) in Supabase backend —
|
|
47
|
+
replaced by shared `responses` table.
|
|
48
|
+
- `BUILD.md` reference removed from MANIFEST.in (file never existed).
|
|
49
|
+
|
|
50
|
+
## [0.4.1] — 2026-04-15
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- Initial public structure with core survey engine, React frontend, CLI,
|
|
55
|
+
local SQLite backend, and Supabase/Vercel deployment support.
|
siamang-0.5.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Siamang Project Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
include README.md CHANGELOG.md LICENSE MANIFEST.in
|
|
2
|
+
include pyproject.toml
|
|
3
|
+
|
|
4
|
+
recursive-include siamang *.tpl *.jsx *.js py.typed
|
|
5
|
+
recursive-include docs *.md
|
|
6
|
+
recursive-include examples *.py
|
|
7
|
+
|
|
8
|
+
global-exclude *.map
|
|
9
|
+
global-exclude *.ts
|
|
10
|
+
global-exclude *.tsx
|
|
11
|
+
global-exclude __pycache__
|
|
12
|
+
global-exclude *.py[cod]
|
|
13
|
+
global-exclude .DS_Store
|
siamang-0.5.0/PKG-INFO
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: siamang
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Research-as-code framework for sociological surveys.
|
|
5
|
+
Author: Siamang Project Contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/hanelias/siamang
|
|
8
|
+
Project-URL: Manual, https://github.com/hanelias/siamang/blob/main/MANUAL.md
|
|
9
|
+
Project-URL: Issues, https://github.com/hanelias/siamang/issues
|
|
10
|
+
Keywords: survey,research,sociology,questionnaire,polling
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Intended Audience :: Education
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Classifier: Topic :: Sociology
|
|
21
|
+
Classifier: Typing :: Typed
|
|
22
|
+
Requires-Python: >=3.11
|
|
23
|
+
Description-Content-Type: text/markdown
|
|
24
|
+
License-File: LICENSE
|
|
25
|
+
Requires-Dist: pandas>=2.0
|
|
26
|
+
Requires-Dist: fastapi>=0.110
|
|
27
|
+
Requires-Dist: uvicorn>=0.29
|
|
28
|
+
Requires-Dist: openpyxl>=3.1
|
|
29
|
+
Requires-Dist: pyreadstat>=1.2
|
|
30
|
+
Requires-Dist: scipy>=1.11
|
|
31
|
+
Requires-Dist: supabase>=2.0
|
|
32
|
+
Requires-Dist: requests>=2.31
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
35
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
37
|
+
Requires-Dist: siamang[charts]; extra == "dev"
|
|
38
|
+
Provides-Extra: charts
|
|
39
|
+
Requires-Dist: matplotlib>=3.7; extra == "charts"
|
|
40
|
+
Requires-Dist: seaborn>=0.13; extra == "charts"
|
|
41
|
+
Provides-Extra: gsheets
|
|
42
|
+
Requires-Dist: google-auth>=2.0; extra == "gsheets"
|
|
43
|
+
Requires-Dist: google-auth-httplib2>=0.1; extra == "gsheets"
|
|
44
|
+
Requires-Dist: google-api-python-client>=2.0; extra == "gsheets"
|
|
45
|
+
Provides-Extra: all
|
|
46
|
+
Provides-Extra: excel
|
|
47
|
+
Provides-Extra: pyreadstat
|
|
48
|
+
Provides-Extra: server
|
|
49
|
+
Provides-Extra: supabase
|
|
50
|
+
Provides-Extra: vercel
|
|
51
|
+
Provides-Extra: scipy
|
|
52
|
+
Dynamic: license-file
|
|
53
|
+
|
|
54
|
+
<h1 align="center">siamang</h1>
|
|
55
|
+
|
|
56
|
+
<p align="center">
|
|
57
|
+
<strong>Research-as-code framework for sociological surveys.</strong><br>
|
|
58
|
+
Define variables, questionnaires, and logic in pure Python — then
|
|
59
|
+
deploy, collect, and analyze in a single pipeline.
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
<p align="center">
|
|
63
|
+
<a href="#quick-start">Quick start</a> ·
|
|
64
|
+
<a href="#full-pipeline-example">Full pipeline example</a> ·
|
|
65
|
+
<a href="docs/reference/">API Reference</a>
|
|
66
|
+
</p>
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install git+https://github.com/hanelias/siamang.git
|
|
72
|
+
siamang validate my_survey.py
|
|
73
|
+
siamang preview my_survey.py # local preview
|
|
74
|
+
siamang deploy my_survey.py --backend supabase --frontend vercel
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## What it does
|
|
80
|
+
|
|
81
|
+
siamang turns a survey into a running web application from a single
|
|
82
|
+
Python script:
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
my_survey.py ← you write this
|
|
86
|
+
│
|
|
87
|
+
├─ siamang validate → catches errors before deployment
|
|
88
|
+
├─ siamang preview → local frontend (hot-reload)
|
|
89
|
+
├─ siamang deploy → Vercel + Supabase (cloud deployment)
|
|
90
|
+
└─ survey.simulate() → synthetic data for testing
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**No GUI builders. No drag-and-drop. No lock-in.** Your survey is a
|
|
94
|
+
Python module — version-control it, test it, reuse it.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Quick start
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
from siamang.core import (
|
|
102
|
+
Variable, SingleChoice, LikertScale, Page, Questionnaire,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
# Define variables with full metadata
|
|
106
|
+
satisfaction = Variable(
|
|
107
|
+
"satisfaction", scale="ordinal",
|
|
108
|
+
label="Overall satisfaction",
|
|
109
|
+
labels={1: "Very dissatisfied", 2: "Dissatisfied",
|
|
110
|
+
3: "Neutral", 4: "Satisfied", 5: "Very satisfied"},
|
|
111
|
+
)
|
|
112
|
+
remote_freq = Variable(
|
|
113
|
+
"remote_freq", scale="ordinal",
|
|
114
|
+
label="Remote work frequency",
|
|
115
|
+
labels={1: "Never", 2: "1-2 days/week",
|
|
116
|
+
3: "3-4 days/week", 4: "Fully remote"},
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
# Build questions
|
|
120
|
+
q_sat = LikertScale("How satisfied are you with your current role?",
|
|
121
|
+
var=satisfaction, points=5, required=True)
|
|
122
|
+
q_remote = SingleChoice("How often do you work remotely?",
|
|
123
|
+
var=remote_freq, display="radio", required=True)
|
|
124
|
+
|
|
125
|
+
# Assemble questionnaire
|
|
126
|
+
survey = Questionnaire(
|
|
127
|
+
title="Work Attitudes Study",
|
|
128
|
+
pages=[Page("main", items=[q_sat, q_remote])],
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Simulate and analyze
|
|
132
|
+
data = survey.simulate(n=200)
|
|
133
|
+
print(data.report.freq("satisfaction").to_markdown())
|
|
134
|
+
|
|
135
|
+
# Visualize (requires: pip install siamang[charts])
|
|
136
|
+
data.plot.bar("satisfaction").show()
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## Full Pipeline Example
|
|
142
|
+
|
|
143
|
+
The [`examples/full_pipeline/`](examples/full_pipeline/) directory contains a complete Jupyter notebook demonstrating the entire research workflow — from survey design to statistical analysis:
|
|
144
|
+
|
|
145
|
+
1. **Survey Design** — 12 variables, 5 pages, conditional routing (`show_if`), matrix questions, Likert scales
|
|
146
|
+
2. **Simulation & Deployment** — 250 synthetic respondents, local SQLite storage, interactive HTML preview
|
|
147
|
+
3. **Declarative Reporting** — frequency tables, cross-tabs with Chi², grouped means with auto-selected tests, correlation heatmaps
|
|
148
|
+
4. **Visualizations** — bar charts, boxplots, heatmaps, scatter plots — all with one line of code
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
cd examples/full_pipeline
|
|
152
|
+
jupyter notebook full_pipeline_demo.ipynb
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The folder also includes `survey_preview.html` — an interactive HTML survey you can open in any browser to see how the questionnaire looks for respondents.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Features
|
|
160
|
+
|
|
161
|
+
| Area | Capabilities |
|
|
162
|
+
| :--- | :--- |
|
|
163
|
+
| **Core** | Variables (nominal/ordinal/interval/ratio), questions (single/multi/open/numeric/likert/matrix/ranking), pages, skip logic (`show_if`/`hide_if`), quotas, validation |
|
|
164
|
+
| **Reporting** | Declarative tables (`FreqTable`, `CrossTable`, `GroupMeanTable`) and charts (`BarChart`, `BoxPlot`, `HeatMap`, `ScatterPlot`) — automatic labels, statistical tests, and metadata awareness |
|
|
165
|
+
| **Scripts** | Inline JavaScript for survey-side behaviour — 7 trigger points |
|
|
166
|
+
| **Frontend** | SurveyJS and React 18 runtimes, dark mode, auto-save, access codes, 6 theme presets |
|
|
167
|
+
| **Backend** | Local SQLite for development, Supabase for production, Google Sheets for collaborative access |
|
|
168
|
+
| **Deploy** | Vercel and Netlify frontends with CSP headers; self-contained HTML bundle for offline use |
|
|
169
|
+
| **Data I/O** | CSV, Excel (.xlsx), SPSS (.sav), Stata (.dta), R (.rda) — round-trip with labels and missing values preserved |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Declarative Reporting API
|
|
174
|
+
|
|
175
|
+
Siamang automatically uses variable metadata (labels, scales, missing values) to produce publication-ready outputs — like SPSS, but in Python:
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
data = survey.simulate(n=300)
|
|
179
|
+
|
|
180
|
+
# Tables — automatic labels, tests, and formatting
|
|
181
|
+
data.report.freq("it_role") # frequency table
|
|
182
|
+
data.report.crosstab("gender", "satisfaction", pct="col") # cross-tab + Chi²
|
|
183
|
+
data.report.means("autonomy", by="remote_freq") # means + Kruskal-Wallis
|
|
184
|
+
|
|
185
|
+
# Charts — one line, automatic axis labels
|
|
186
|
+
data.plot.bar("it_role")
|
|
187
|
+
data.plot.boxplot("satisfaction", by="remote_freq", show_points=True)
|
|
188
|
+
data.plot.heatmap(["surv_keystroke", "surv_camera"], by="remote_freq")
|
|
189
|
+
data.plot.scatter("satisfaction", "autonomy", hue="gender")
|
|
190
|
+
|
|
191
|
+
# Export
|
|
192
|
+
data.report.freq("it_role").to_markdown() # Markdown string
|
|
193
|
+
data.report.freq("it_role").to_frame() # pandas DataFrame
|
|
194
|
+
data.report.freq("it_role").to_html() # HTML table
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## Deployment
|
|
200
|
+
|
|
201
|
+
### Local (development)
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
siamang preview my_survey.py # → http://127.0.0.1:8000
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Cloud — Vercel + Supabase (high concurrency)
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
siamang init # one-time: stores credentials
|
|
211
|
+
siamang deploy my_survey.py --backend supabase --frontend vercel
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### Cloud — Netlify + Google Sheets (lightweight)
|
|
215
|
+
|
|
216
|
+
```bash
|
|
217
|
+
export SIAMANG_GSHEETS_CREDENTIALS_FILE=./service-account-key.json
|
|
218
|
+
export NETLIFY_AUTH_TOKEN=nfp_...
|
|
219
|
+
siamang deploy my_survey.py --backend gsheets --frontend netlify
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Responses are written to a Google Spreadsheet (one row per respondent) via an **Apps Script proxy** that acts as a secure intermediary. The survey is hosted on Netlify CDN with automatic HTTPS and global edge distribution.
|
|
223
|
+
|
|
224
|
+
> **Note:** The Google Sheets backend is currently **experimental** for public web deployments. Browser-to-Sheets writes require an Apps Script Web App URL to avoid exposing credentials. See [`docs/reference/deploy.md`](docs/reference/deploy.md#googlesheetsbackend) for setup instructions.
|
|
225
|
+
|
|
226
|
+
### Deployment combinations
|
|
227
|
+
|
|
228
|
+
| Use case | Backend | Frontend |
|
|
229
|
+
| :--- | :--- | :--- |
|
|
230
|
+
| Local development / testing | `local` | `local` |
|
|
231
|
+
| Small survey, shared with team | `gsheets` | `netlify` |
|
|
232
|
+
| Production, high concurrency | `supabase` | `vercel` or `netlify` |
|
|
233
|
+
| Offline / air-gapped | `local` | `local` (HTML bundle) |
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
## Project Layout
|
|
238
|
+
|
|
239
|
+
```
|
|
240
|
+
siamang/
|
|
241
|
+
├── core/ Variable, Question types, Block, Page, Questionnaire, Expression, Quota, Script
|
|
242
|
+
├── data/ SurveyData, DataAnalysis, DataProcessing, SurveyTables
|
|
243
|
+
├── reporting/ Declarative tables (FreqTable, CrossTable, GroupMeanTable) and charts (BarChart, BoxPlot, HeatMap, ScatterPlot)
|
|
244
|
+
├── frontend/ SurveyJS & React runtimes, bundle builder, UIConfig theme engine, presets
|
|
245
|
+
├── deploy/ Backends (SQLite, Supabase, Google Sheets), frontends (Vercel, Netlify, local), pipeline orchestration
|
|
246
|
+
├── cli/ validate, preview, deploy, init
|
|
247
|
+
├── io/ Import/export for CSV, Excel, SPSS, Stata, R
|
|
248
|
+
└── config/ User configuration (~/.siamang.toml), secrets
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Documentation
|
|
254
|
+
|
|
255
|
+
| Resource | Description |
|
|
256
|
+
| :--- | :--- |
|
|
257
|
+
| [`docs/reference/core.md`](docs/reference/core.md) | API reference — Variable, Expression, all Question types, Page, Questionnaire |
|
|
258
|
+
| [`docs/reference/data.md`](docs/reference/data.md) | API reference — SurveyData, DataAnalysis, DataProcessing, SurveyTables |
|
|
259
|
+
| [`docs/reference/reporting.md`](docs/reference/reporting.md) | API reference — Declarative tables and charts |
|
|
260
|
+
| [`docs/reference/frontend.md`](docs/reference/frontend.md) | API reference — UIConfig, theme presets, runtimes, bundle builder |
|
|
261
|
+
| [`docs/reference/deploy.md`](docs/reference/deploy.md) | API reference — Backends (Local, Supabase, Google Sheets), Frontends (Local, Vercel, Netlify), pipeline |
|
|
262
|
+
| [`examples/full_pipeline/`](examples/full_pipeline/) | Complete worked example: design → deploy → analyze |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## Requirements
|
|
267
|
+
|
|
268
|
+
- **Python 3.11+**
|
|
269
|
+
- For cloud deployment (option A): a **Supabase** project and a **Vercel** account
|
|
270
|
+
- For cloud deployment (option B): a **Google Cloud** service account and a **Netlify** account
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Dependencies
|
|
275
|
+
|
|
276
|
+
All core dependencies are installed automatically with `pip install siamang`.
|
|
277
|
+
|
|
278
|
+
### Core (installed automatically)
|
|
279
|
+
|
|
280
|
+
| Package | Version | Purpose |
|
|
281
|
+
| :--- | :--- | :--- |
|
|
282
|
+
| `pandas` | ≥ 2.0 | Data manipulation, SurveyData backbone |
|
|
283
|
+
| `scipy` | ≥ 1.11 | Statistical tests (chi-square, t-test, ANOVA) |
|
|
284
|
+
| `openpyxl` | ≥ 3.1 | Excel (.xlsx) import/export |
|
|
285
|
+
| `pyreadstat` | ≥ 1.2 | SPSS (.sav) and Stata (.dta) import/export |
|
|
286
|
+
| `fastapi` | ≥ 0.110 | Local preview server (`siamang preview`) |
|
|
287
|
+
| `uvicorn` | ≥ 0.29 | ASGI server for local preview |
|
|
288
|
+
| `supabase` | ≥ 2.0 | Supabase backend (Postgres + RLS + Edge Functions) |
|
|
289
|
+
| `requests` | ≥ 2.31 | HTTP client for Netlify/Vercel deployment APIs |
|
|
290
|
+
|
|
291
|
+
### Charts (optional)
|
|
292
|
+
|
|
293
|
+
```bash
|
|
294
|
+
pip install siamang[charts]
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
| Package | Version | Purpose |
|
|
298
|
+
| :--- | :--- | :--- |
|
|
299
|
+
| `matplotlib` | ≥ 3.7 | Chart rendering (`data.plot.bar()`, `.boxplot()`, `.scatter()`, `.heatmap()`) |
|
|
300
|
+
| `seaborn` | ≥ 0.13 | Statistical visualization helpers |
|
|
301
|
+
|
|
302
|
+
Charts are optional — if you only use tables (`data.report.freq()`, `data.report.crosstab()`), matplotlib is not needed. A clear error message will guide you if you try to render a chart without it.
|
|
303
|
+
|
|
304
|
+
### Google Sheets backend (optional)
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
pip install siamang[gsheets]
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
| Package | Version | Purpose |
|
|
311
|
+
| :--- | :--- | :--- |
|
|
312
|
+
| `google-auth` | ≥ 2.0 | Service account authentication |
|
|
313
|
+
| `google-auth-httplib2` | ≥ 0.1 | HTTP transport for Google APIs |
|
|
314
|
+
| `google-api-python-client` | ≥ 2.0 | Google Sheets API and Google Drive API client |
|
|
315
|
+
|
|
316
|
+
### Development
|
|
317
|
+
|
|
318
|
+
```bash
|
|
319
|
+
pip install siamang[dev]
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
| Package | Version | Purpose |
|
|
323
|
+
| :--- | :--- | :--- |
|
|
324
|
+
| `ruff` | ≥ 0.4 | Linting and formatting |
|
|
325
|
+
| `mypy` | ≥ 1.10 | Static type checking |
|
|
326
|
+
| `pytest` | ≥ 8.0 | Test runner |
|
|
327
|
+
| `matplotlib` | ≥ 3.7 | Required for chart tests |
|
|
328
|
+
| `seaborn` | ≥ 0.13 | Required for chart tests |
|
|
329
|
+
|
|
330
|
+
---
|
|
331
|
+
|
|
332
|
+
## License
|
|
333
|
+
|
|
334
|
+
Siamang is released under the [MIT License](LICENSE). Free for any use —
|
|
335
|
+
academic, commercial, personal.
|