Skip to main content

A simple, elegant Python framework for creating and running interactive quizzes

Project description

Quizy

Overview

A lightweight, API-first Python quiz framework for creating interactive quizzes and assessments. Quizy provides a clean, extensible interface without prescriptive UI constraints, allowing you to build quiz applications that fit your specific needs.

  • Async/Await Support: Non-blocking quiz execution with execute_async()
  • Live Timer Display: Real-time countdown with visual feedback
  • Partial Credit System: Award points for partially correct answers
  • Enhanced MatchingQuestion: Answer shuffling and optional partial credit
  • Improved CLI: Interactive formatting with progress indicators
  • Better Time Management: Per-question and quiz-level time limits with countdown

Important: Unified API

As of v0.3.0, all enhanced features are integrated directly into the core API. There are no separate "improved" modules:

# Single unified import
from quizy import Quiz, MatchingQuestion, QuizCLI, TimerDisplay

# All features are available by default
quiz = Quiz(title="My Quiz", time_limit=60)

1. Async Quiz Execution

Execute quizzes asynchronously for non-blocking operations:

from quizy import Quiz, MultipleChoiceQuestion, QuizCLI

quiz = Quiz(title="Async Quiz")
# ... add questions ...

# Run asynchronously
result = await quiz.execute_async(
    answer_provider=async_answer_provider,
    question_callback=async_question_callback
)

2. Enhanced MatchingQuestion

New options for better user experience:

from quizy import MatchingQuestion

question = MatchingQuestion(
    text="Match items",
    pairs={"A": "Apple", "B": "Banana", "C": "Cherry"},
    shuffle_answers=True,        # NEW: Randomize answer options (default: True)
    allow_partial_credit=False,  # NEW: Award partial points (default: False)
    time_limit=15                # Time limit in seconds
)

Partial Credit Calculation:

  • Full match: 100% credit
  • Partial match: correct_matches / total_pairs
  • Wrong selections: 0% credit

3. Partial Credit for MultipleSelectQuestion

Award partial credit for incomplete correct answers:

from quizy import MultipleSelectQuestion

question = MultipleSelectQuestion(
    text="Select all correct answers",
    options=["A", "B", "C", "D"],
    correct_answers=["A", "B"],
    allow_partial_credit=True,  # NEW
    shuffle_options=True
)

4. Live Timer Display

Display countdown timers with visual feedback:

from quizy import TimerDisplay

# Create a timer for a question
timer = TimerDisplay(duration=15)  # 15 seconds

# Check remaining time
remaining = timer.get_remaining()
time_string = timer.format_time(remaining)  # "00:05"

# Visual warning
warning = timer.get_warning_symbol()  # Returns ⚠️, ⏱️, or ✓

Time Warning Indicators:

  • - Plenty of time (>30s remaining)
  • ⏱️ - Getting short (10-30s remaining)
  • ⚠️ - Running out (≤10s remaining)
  • - Time expired

5. Enhanced Results with Metrics

New metrics in QuizResult:

result = quiz.execute(answer_provider=provide_answer)

# New properties
print(f"Score: {result.score_percentage:.1f}%")           # Includes partial credit
print(f"Partial Answers: {result.partial_answers}")       # Count of partial credit
print(f"Avg Time/Question: {result.average_time_per_question:.1f}s")

# New in QuestionResult
for qr in result.question_results:
    print(f"Score: {qr.score}")      # 0.0 to 1.0 (0.5 for partial)
    print(f"Is Partial: {qr.is_partial}")

6. Question Shuffling

Shuffle options for variety and fairness:

from quizy import MultipleChoiceQuestion

# Shuffle for this question
q1 = MultipleChoiceQuestion(
    text="What is 2+2?",
    options=["3", "4", "5"],
    correct_answer="4",
    shuffle_options=True
)

# Access shuffled display options
for opt in q1.display_options:
    print(opt)

7. Quiz Randomization

Randomize quiz question order:

quiz = Quiz(
    title="My Quiz",
    randomize_order=True,  # Shuffle question order
    shuffle_options=True,  # Shuffle all question options
    show_progress=True     # Show progress indicator
)

Enhanced CLI Features

Interactive Formatting

The QuizCLI now provides:

  • Color-coded output: Green for correct, red for incorrect, yellow for warnings
  • Visual status icons: ✓, ✗, ◐, ⏱, ⊘ for different result types
  • Progress indicators: Question numbering with remaining time
  • Better prompts: Context-aware input requests

Example Output

============================================================
Question 1/5 | ⏱️  15s
============================================================

What is the capital of France?

  1. London
  2. Berlin
  3. Paris
  4. Madrid

⏱️  Time remaining: 00:12
Your answer (1-4): 3

============================================================
  Results: Quiz Title
============================================================

Overall Performance:
  Total Questions:     5
  Correct Answers:     4
  Partial Answers:     1
  Score:               90.0%
  Time Taken:          00:34
  Avg Time/Question:   6.8s

Running Interactive Quiz

from quizy import QuizCLI

# With timer display
QuizCLI.run_interactive(quiz, show_timer=True)

# Async version
await QuizCLI.run_interactive_async(quiz, show_timer=True)

Showing Detailed Results

# Display breakdown for each question
QuizCLI.display_detailed_results(result)

API Compatibility

Unified Single API

v0.3.0 uses a single unified API. All enhanced features are directly integrated:

# Single import source
from quizy import (
    Quiz,
    MultipleChoiceQuestion,
    MatchingQuestion,
    QuizCLI,
    TimerDisplay
)

# All features available by default
quiz = Quiz(title="My Quiz", time_limit=60)

No "Improved" Modules

There are no separate core_improved.py or cli_improved.py modules. The original core.py and cli.py have been replaced with the enhanced versions.

Performance Considerations

Async vs Sync

Use execute() when:

  • Simple synchronous answer providers
  • No blocking I/O operations
  • Standard quiz application

Use execute_async() when:

  • Answer provider makes network calls
  • Integrating with web servers (FastAPI, Django)
  • Real-time quiz systems
  • Complex async workflows

Timer Overhead

Timer display has minimal overhead:

  • Time checking: ~0.1ms per check
  • Display formatting: ~0.5ms per update
  • No separate threads needed (can be added for UI updates)

Migration Guide

From v0.2 to v0.3

  1. Questions still work the same:

    # v0.2
    q = MultipleChoiceQuestion(text="?", options=[...], correct_answer="...")
    
    # v0.3 - same, but can add new features
    q = MultipleChoiceQuestion(
        text="?",
        options=[...],
        correct_answer="...",
        shuffle_options=True  # NEW option
    )
    
  2. Add timer support gradually:

    # Add time_limit to existing questions
    q.time_limit = 15  # or in constructor
    
  3. Update imports if using enhanced features:

    # For async, use core_improved
    from quizy.core_improved import Quiz
    

Examples

Complete Example: Timed Quiz with Async

import asyncio
from quizy import (
    Quiz,
    MultipleChoiceQuestion,
    MatchingQuestion,
    QuizCLI
)

async def main():
    quiz = Quiz(
        title="Python Fundamentals",
        time_limit=120,  # 2 minutes total
        allow_skip=False,
        shuffle_options=True,
        randomize_order=True
    )
    
    # Add timed questions
    quiz.add_question(MultipleChoiceQuestion(
        text="What does OOP stand for?",
        options=["Object Oriented Programming", "Other Object Patterns", "Outer Object Procedure"],
        correct_answer="Object Oriented Programming",
        time_limit=10
    ))
    
    quiz.add_question(MatchingQuestion(
        text="Match methods to descriptions",
        pairs={
            "__init__": "Constructor",
            "__str__": "String representation",
            "__len__": "Length"
        },
        shuffle_answers=True,
        allow_partial_credit=False,  # Disable by default
        time_limit=20
    ))
    
    # Run async
    result = await quiz.execute_async(
        answer_provider=async_get_answer,
        question_callback=async_display_question
    )
    
    QuizCLI.display_result(result)

async def async_get_answer(question, idx):
    # Your async answer logic here
    return "answer"

async def async_display_question(question, idx, total):
    # Your async display logic here
    pass

# Run
asyncio.run(main())

Known Limitations

  1. Terminal-based timer: Countdown display works best in interactive terminals
  2. Async input: Currently uses blocking input() - can be enhanced with aioinput
  3. Option shuffling: Once shuffled, cannot be re-shuffled in same instance
  4. Partial credit: Some question types (Short Text) don't support partial credit

Future Enhancements

Planned for v0.4+:

  • Web-based UI components
  • Database integration for result persistence
  • Advanced analytics and reporting
  • Real-time leaderboards
  • Ai-powered question generation
  • More partial credit options

Support & Contributions

For issues, feature requests, or contributions:

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

quizy-0.3.1.tar.gz (20.3 kB view details)

Uploaded Source

Built Distribution

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

quizy-0.3.1-py3-none-any.whl (16.8 kB view details)

Uploaded Python 3

File details

Details for the file quizy-0.3.1.tar.gz.

File metadata

  • Download URL: quizy-0.3.1.tar.gz
  • Upload date:
  • Size: 20.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for quizy-0.3.1.tar.gz
Algorithm Hash digest
SHA256 525076ecfb738feb38a29bf0f707213ba152547e24aee73b8922f3163411ede5
MD5 5fdbfd6fb08b5eb4dbb182f51027a2f8
BLAKE2b-256 cb381fd9d4b25c00d2ff419a0e40016a578632ab725f61db9a2053ce1c19ff00

See more details on using hashes here.

File details

Details for the file quizy-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: quizy-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 16.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.5

File hashes

Hashes for quizy-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 97064874b6950d11b232f9d27f61e630f41a4e89645407697e9ecea47f268e54
MD5 e2f5cba122322d9e95d81ae44da56688
BLAKE2b-256 9cb323a780223b86be17a3ab5fdaf8d994020c01f5e87ab753f55313395e246e

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