Skip to main content

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 question
  • option.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 example
  • llm_tools_demo.py - Complete LLM integration demo
  • quick_start.py - Basic usage patterns

Feature Demonstrations

  • validation_demo.py - Answer validation examples
  • import_export_demo.py - Format conversion
  • quecode_demo.py - QueCode format guide
  • complete_workflow.py - Full interactive flow
  • interactive_flow.py - Step-by-step navigation

Sample Questionnaires

  • simple_survey.yaml - 3 questions, linear flow
  • athlete_habits.yaml - 17 questions, complex branching
  • product_recommendation.yaml - 8 questions, user-type routing
  • medical_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 guide
  • examples/README_LLM_TOOLS.md - LLM tools overview
  • examples/QUECODE_GUIDE.md - QueCode format reference
  • examples/IMPORT_EXPORT_GUIDE.md - Format conversion guide
  • examples/IO_QUICK_REFERENCE.md - I/O API cheatsheet

Developer Documentation

  • CLAUDE.md - Project overview and architecture
  • schema.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.md and inline docstrings
  • Issues: [Report issues on GitHub]
  • Questions: [Add contact method or discussion forum]

Built with ❤️ for creating intelligent questionnaires

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

quaestionario-0.1.0.tar.gz (37.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

quaestionario-0.1.0-py3-none-any.whl (27.4 kB view details)

Uploaded Python 3

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

Hashes for quaestionario-0.1.0.tar.gz
Algorithm Hash digest
SHA256 de266f299c52db05a1a17bd28d807652a1c50014b235f5c3e61170b8b121d567
MD5 88e2ff3026def725bdaead077906acae
BLAKE2b-256 34645a66f9d0f9f656f55e661eacc3ffe01871552680b2d863680a1f4ee03338

See more details on using hashes here.

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

Hashes for quaestionario-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 c73196289735a2befc34d1d3fa063033b9ee787bbfab6f8ab23244df841c269f
MD5 9daada9a4b00198aa868984db4415e04
BLAKE2b-256 164156aebf980e67fa1b82ae5ab2495b30f4aaf391bfd27aea41aea934ba02e7

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page