A Python package for managing questionnaires as weakly connected rooted directed acyclic graphs
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file quaestionario-0.1.0.tar.gz.
File metadata
- Download URL: quaestionario-0.1.0.tar.gz
- Upload date:
- Size: 37.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de266f299c52db05a1a17bd28d807652a1c50014b235f5c3e61170b8b121d567
|
|
| MD5 |
88e2ff3026def725bdaead077906acae
|
|
| BLAKE2b-256 |
34645a66f9d0f9f656f55e661eacc3ffe01871552680b2d863680a1f4ee03338
|
File details
Details for the file quaestionario-0.1.0-py3-none-any.whl.
File metadata
- Download URL: quaestionario-0.1.0-py3-none-any.whl
- Upload date:
- Size: 27.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c73196289735a2befc34d1d3fa063033b9ee787bbfab6f8ab23244df841c269f
|
|
| MD5 |
9daada9a4b00198aa868984db4415e04
|
|
| BLAKE2b-256 |
164156aebf980e67fa1b82ae5ab2495b30f4aaf391bfd27aea41aea934ba02e7
|