Quaestionario
Intelligent questionnaire management for Python
Quaestionario is a powerful Python package for creating, managing, and analyzing questionnaires as directed acyclic graphs (DAGs). It provides a clean API for building complex surveys with conditional branching, multi-format support, and AI-powered analysis capabilities.
Features
Core Capabilities
- 📊 DAG-based Structure - Questionnaires as weakly connected rooted directed acyclic graphs
- ✅ Robust Validation - Type checking, range validation, and constraint enforcement
- 🔀 Conditional Branching - Questions that appear based on previous answers
- 🧠 AI-Powered Analysis - Path exploration, dependency tracking, and complexity metrics
- 📝 Multi-Format Support - JSON, YAML, and QueCode (compact DSL)
- 🔒 Type-Safe - Built on Pydantic v2 with full type hints
- 🎯 LLM-Ready - Simple stateless API perfect for chatbots and conversational AI
Question Types
Support for 8 question types covering all common use cases:
- Boolean (Yes/No)
- Text (Short & Long)
- Number
- DateTime
- Scale (with min/max/step)
- Single Choice
- Multi Choice
Quick Start
Installation
# Using pip
pip install -e .
# Using uv (recommended)
uv sync
Basic Usage
from quaestionario import Questionnaire, QuestionnaireAnalyzer, AnswerValidator
# Load a questionnaire (supports .json, .yaml, .qc)
from quaestionario import load_questionnaire
questionnaire = load_questionnaire("survey.yaml")
# Navigate through questions
analyzer = QuestionnaireAnalyzer(questionnaire)
answers = {}
while True:
# Get next question
next_q_id = analyzer.get_next_question(answers)
if next_q_id is None:
break # Questionnaire complete
question = questionnaire.get_question_by_id(next_q_id)
# Validate answer
validator = AnswerValidator()
user_answer = get_user_input(question.text)
result = validator.validate_answer(question, user_answer)
if result.is_valid:
answers[next_q_id] = user_answer
else:
print(f"Invalid: {result.errors[0]}")
print(f"Collected {len(answers)} answers!")
Format Support
Quaestionario supports three formats for defining questionnaires:
JSON
{
"questionnaireId": "survey-v1",
"startQuestion": "Q1",
"questions": [
{
"id": "Q1",
"type": "scale",
"text": "How satisfied are you?",
"min": 1,
"max": 5
}
]
}
YAML
questionnaireId: survey-v1
startQuestion: Q1
questions:
- id: Q1
type: scale
text: How satisfied are you?
min: 1
max: 5
QueCode (Compact DSL)
quecode id="survey-v1" start=Q1
Q1 scale "How satisfied are you?"
min 1
max 5
QueCode is 35% smaller than YAML and 56% smaller than JSON!
All formats are fully interchangeable:
from quaestionario import convert_questionnaire
# Convert between formats
convert_questionnaire("input.yaml", "output.qc")
convert_questionnaire("input.json", "output.yaml")
LLM Integration
Quaestionario is designed for seamless integration with LLMs and conversational AI:
from quaestionario import Questionnaire, QuestionnaireAnalyzer
def next_question(schema: dict, answers: dict) -> dict:
"""Get next question - perfect for LLM function calling."""
questionnaire = Questionnaire(**schema)
analyzer = QuestionnaireAnalyzer(questionnaire)
next_id = analyzer.get_next_question(answers)
if next_id is None:
return {"is_complete": True}
question = questionnaire.get_question_by_id(next_id)
return {
"question_id": next_id,
"question": {
"text": question.text,
"type": question.type,
...
},
"is_complete": False
}
Why it works great for LLMs:
- ✅ Stateless - just pass schema and current answers
- ✅ JSON in/out - universal format
- ✅ No session management needed
- ✅ Automatic branching and validation
- ✅ Clear error messages for user feedback
See examples/llm_tools_demo.py for complete examples.
Advanced Analysis
Quaestionario includes powerful AI-powered analysis capabilities:
from quaestionario import QuestionnaireAnalyzer
analyzer = QuestionnaireAnalyzer(questionnaire)
# Always required questions (appear in ALL paths)
required = analyzer.get_always_required_questions(answers)
# Optimal next questions (unblock the most dependencies)
optimal = analyzer.get_optimal_next_questions(answers, max_suggestions=3)
# Completion bounds
min_q, max_q = analyzer.get_completion_bounds(answers)
print(f"Between {min_q} and {max_q} questions remaining")
# Complexity metrics
complexity = analyzer.analyze_questionnaire_complexity()
print(f"Total questions: {complexity['total_questions']}")
print(f"Conditional questions: {complexity['conditional_questions']}")
print(f"Max depth: {complexity['max_depth']}")
# Simulate all possible paths
paths = analyzer.simulate_questionnaire_paths(max_paths=100)
print(f"Found {len(paths)} unique completion paths")
Architecture
Core Components
quaestionario/
├── models.py # Pydantic models for questions and questionnaires
├── graph.py # DAG validation and navigation
├── analyzer.py # AI-powered path analysis
├── validation.py # Answer validation
└── io/ # Multi-format import/export
├── json_format.py
├── yaml_format.py
└── quecode_format.py
Key Concepts
Dual Navigation System:
default_next- Default next questionoption.next- Option-specific navigation (takes precedence)
Conditional Logic:
- Questions can have conditions based on previous answers
- Supports operators:
=,!=,<,<=,>,>=,contains,in,exists, etc.
Path-Aware Analysis:
- Distinguishes between "reachable" and "always required"
- Critical for understanding questionnaire completion requirements
See CLAUDE.md for detailed architecture documentation.
Examples
The examples/ directory contains comprehensive demonstrations:
Quick Start Examples
minimal_llm_example.py- 50-line minimal examplellm_tools_demo.py- Complete LLM integration demoquick_start.py- Basic usage patterns
Feature Demonstrations
validation_demo.py- Answer validation examplesimport_export_demo.py- Format conversionquecode_demo.py- QueCode format guidecomplete_workflow.py- Full interactive flowinteractive_flow.py- Step-by-step navigation
Sample Questionnaires
simple_survey.yaml- 3 questions, linear flowathlete_habits.yaml- 17 questions, complex branchingproduct_recommendation.yaml- 8 questions, user-type routingmedical_screening.yaml- 13 questions, conditional logic
All samples available in .json, .yaml, and .qc formats!
Run Examples
# Minimal example (starts in seconds)
python examples/minimal_llm_example.py
# Full LLM tools demo
python examples/llm_tools_demo.py
# Validation demo
python examples/validation_demo.py
# Interactive questionnaire
python examples/interactive_flow.py
Documentation
Quick Reference Guides
examples/LLM_TOOLS_QUICK_START.md- LLM integration guideexamples/README_LLM_TOOLS.md- LLM tools overviewexamples/QUECODE_GUIDE.md- QueCode format referenceexamples/IMPORT_EXPORT_GUIDE.md- Format conversion guideexamples/IO_QUICK_REFERENCE.md- I/O API cheatsheet
Developer Documentation
CLAUDE.md- Project overview and architectureschema.json- JSON schema definition- API Documentation - Inline docstrings throughout codebase
Development
Setup
# Clone and setup
git clone <repository-url>
cd Quaestionario
uv sync
# Or with pip
pip install -r requirements.txt
Testing
# Run all tests
python -m pytest tests/ -v
# Run without coverage
python -m pytest tests/ -v --no-cov
# Run specific test file
python -m pytest tests/test_models.py -v
# Run specific test
python -m pytest tests/test_models.py::test_basic_questionnaire_creation -v
Code Quality
# Format code
black quaestionario tests
# Sort imports
isort quaestionario tests
# Type check
mypy quaestionario
Build
# Build package
python -m build
# Install in development mode
pip install -e .
Use Cases
Quaestionario is perfect for:
- 🤖 Chatbots & Conversational AI - LLM-friendly stateless API
- 📋 Survey Platforms - Complex branching logic and validation
- 🏥 Medical Screening - Conditional questions based on symptoms
- 🎯 Product Recommendations - User profiling with dynamic paths
- 📊 Research Studies - Multi-format export and analysis
- 🔧 Form Builders - Type-safe schema validation
- 🎤 Voice Assistants - Clean Q&A flow with validation
Requirements
- Python 3.13+ (uses modern type hints)
- Pydantic 2.0+ (for data validation)
- PyYAML (for YAML support)
See requirements.txt for complete dependencies.
Project Status
Quaestionario is actively developed and feature-complete for core functionality:
- ✅ All question types implemented
- ✅ DAG validation and navigation
- ✅ Multi-format support (JSON, YAML, QueCode)
- ✅ Answer validation
- ✅ AI-powered analysis
- ✅ Comprehensive test coverage
- ✅ LLM integration examples
- ✅ Full documentation
Contributing
Contributions are welcome! Areas for contribution:
- Additional question types
- More analysis algorithms
- Format converters for other systems
- Documentation improvements
- Example questionnaires
- Bug reports and fixes
License
[Add your license here - e.g., MIT, Apache 2.0, etc.]
Related Projects
- Pydantic - Data validation library
- PyYAML - YAML parser for Python
Support
- Examples: See
examples/directory - Documentation: Check
CLAUDE.mdand inline docstrings - Issues: [Report issues on GitHub]
- Questions: [Add contact method or discussion forum]
Built with ❤️ for creating intelligent questionnaires
Release files for quaestionario 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| quaestionario-0.1.0.tar.gz | 37.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| quaestionario-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 65.3 kB
Release files / quaestionario-0.1.0.tar.gz
| Download URL | quaestionario-0.1.0.tar.gz |
|---|---|
| Size | 37.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
de266f299c52db05a1a17bd28d807652a1c50014b235f5c3e61170b8b121d567
|
|
BLAKE2b-256 checksum How to use checksums |
34645a66f9d0f9f656f55e661eacc3ffe01871552680b2d863680a1f4ee03338
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|
Release files / quaestionario-0.1.0-py3-none-any.whl
| Download URL | quaestionario-0.1.0-py3-none-any.whl |
|---|---|
| Size | 27.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c73196289735a2befc34d1d3fa063033b9ee787bbfab6f8ab23244df841c269f
|
|
BLAKE2b-256 checksum How to use checksums |
164156aebf980e67fa1b82ae5ab2495b30f4aaf391bfd27aea41aea934ba02e7
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.13.7
|