Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 3 additions & 11 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ name: Tests and Coverage

on:
push:
branches: [ main, develop ]
branches: [ main, dev ]
pull_request:
branches: [ main, develop ]
branches: [ main, dev ]

jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
python-version: ["3.9", "3.10", "3.11", "3.12"]
python-version: ["3.10", "3.11", "3.12"]

steps:
- name: Checkout code
Expand Down Expand Up @@ -61,11 +61,3 @@ jobs:
run: |
pytest tests/ -v --cov=veta --cov-append --cov-report=xml --cov-report=term-missing -m "integration"

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
file: ./coverage.xml
flags: unittests
name: codecov-umbrella
fail_ci_if_error: false

4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -116,5 +116,7 @@ __pycache__
*.!*
*pid.txt
.coverage*
coverage.xml
*_pid.txt
rec_0001*
rec_0001*
*.log
106 changes: 106 additions & 0 deletions examples/logging_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env python3
"""
Example script demonstrating the veta logging system.

This script shows how to initialize and use the comprehensive logging
system throughout the veta package.
"""

# Import veta components and logging
from veta import setup_logging, get_logger
from veta.survey import Survey
from veta.respondent import Respondent
from veta.item import Item

def main():
"""Main function demonstrating veta logging capabilities."""

# Example 1: Basic logging setup with auto-generated log file
print("=== Example 1: Basic Logging Setup ===")
setup_logging(
level='INFO',
console_level='INFO',
file_level='DEBUG',
auto_generate_file=True
)

# Get a logger for this example
logger = get_logger('example')
logger.info("Starting veta logging demonstration")

# Example 2: Create a survey and demonstrate logging
print("\n=== Example 2: Survey Operations with Logging ===")
survey = Survey()
logger.info("Created new survey")

# Add some respondents
for i in range(3):
respondent = Respondent(userid=f"user_{i:03d}")

# Add some items to each respondent
respondent.add_item("I feel happy today", "She seems sad")
respondent.add_item("I am excited", "He looks worried")

survey.add_respondent(respondent)

logger.info(f"Survey now has {len(survey.respondents)} respondents")

# Example 3: Different log levels demonstration
print("\n=== Example 3: Different Log Levels ===")
logger.debug("This is a debug message - detailed information")
logger.info("This is an info message - general information")
logger.warning("This is a warning message - something needs attention")
logger.error("This is an error message - something went wrong")

# Example 4: Module-specific loggers
print("\n=== Example 4: Module-specific Loggers ===")
item_logger = get_logger('item_processing')
respondent_logger = get_logger('respondent_analysis')

item_logger.info("Processing individual items")
respondent_logger.info("Analyzing respondent data")

# Example 5: Demonstrate error handling with logging
print("\n=== Example 5: Error Handling with Logging ===")
try:
# This will create a warning/error in the wordlist loading
item = Item("Test sentence")
# Attempting to score without wordlist should generate logs
logger.warning("Attempting operation that may fail...")

except Exception as e:
logger.error(f"Operation failed: {str(e)}")
logger.debug("This would contain detailed stack trace information")

logger.info("Veta logging demonstration completed")
print("\n=== Logging Demonstration Complete ===")
print("Check the generated log file for detailed debug information!")

def demonstrate_custom_logging():
"""Demonstrate custom logging configuration."""
print("\n=== Custom Logging Configuration Example ===")

# Setup logging with custom file and levels
setup_logging(
level='DEBUG',
log_file='./custom_veta_analysis.log',
console_output=True,
file_level='DEBUG',
console_level='WARNING', # Only show warnings and errors in console
auto_generate_file=False
)

custom_logger = get_logger('custom_analysis')

# These will appear in the log file but not console (due to console_level='WARNING')
custom_logger.debug("Detailed debug info - only in file")
custom_logger.info("General info - only in file")

# This will appear in both console and file
custom_logger.warning("Warning message - appears in both console and file")

print("Custom logging example complete - check 'custom_veta_analysis.log'")

if __name__ == "__main__":
main()
demonstrate_custom_logging()
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ requests>=2.25.0
seaborn>=0.11.0
scikit-learn>=1.0.0
scipy>=1.7.0
colorama>=0.4.0

# Testing dependencies
pytest>=7.0.0
Expand Down
166 changes: 166 additions & 0 deletions tests/test_logging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
"""
Test script for the veta logging system.
"""

import pytest
import logging
import tempfile
import os
from pathlib import Path
from veta.logger import setup_logging, get_logger, VetaLogger

class TestVetaLogging:
"""Test cases for the veta logging system."""

def test_basic_logger_setup(self):
"""Test basic logger initialization."""
logger = get_logger('test')
assert isinstance(logger, logging.Logger)
assert logger.name == 'veta.test'

def test_main_logger(self):
"""Test getting the main logger."""
logger = get_logger()
assert isinstance(logger, logging.Logger)
assert logger.name == 'veta'

def test_custom_log_file(self):
"""Test logging to a custom file."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.log', delete=False) as f:
log_file = f.name

try:
setup_logging(
level='DEBUG',
log_file=log_file,
console_output=False,
auto_generate_file=False
)

logger = get_logger('test_file')
logger.info("Test message")

# Check if file was created and contains our message
assert os.path.exists(log_file)
with open(log_file, 'r') as f:
content = f.read()
assert "Test message" in content
assert "test_file" in content
finally:
if os.path.exists(log_file):
os.unlink(log_file)

def test_auto_generate_log_file(self):
"""Test auto-generation of log files."""
# Setup with auto-generate
setup_logging(auto_generate_file=True, console_output=False)

logger = get_logger('test_auto')
logger.info("Auto-generated test message")

# Check that the main veta logger has handlers (child loggers don't have direct handlers)
main_logger = get_logger()
assert len(main_logger.handlers) > 0

def test_different_log_levels(self):
"""Test different logging levels."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.log', delete=False) as f:
log_file = f.name

try:
setup_logging(
level='DEBUG',
log_file=log_file,
console_output=False,
file_level='DEBUG'
)

logger = get_logger('test_levels')
logger.debug("Debug message")
logger.info("Info message")
logger.warning("Warning message")
logger.error("Error message")

# Check all messages are in the file
with open(log_file, 'r') as f:
content = f.read()
assert "Debug message" in content
assert "Info message" in content
assert "Warning message" in content
assert "Error message" in content
finally:
if os.path.exists(log_file):
os.unlink(log_file)

def test_singleton_logger(self):
"""Test that VetaLogger follows singleton pattern."""
logger1 = VetaLogger()
logger2 = VetaLogger()
assert logger1 is logger2

def test_logger_formatting(self):
"""Test that log messages contain expected formatting elements."""
with tempfile.NamedTemporaryFile(mode='w', suffix='.log', delete=False) as f:
log_file = f.name

try:
setup_logging(
level='DEBUG',
log_file=log_file,
console_output=False
)

logger = get_logger('test_format')
logger.info("Format test message")

with open(log_file, 'r') as f:
content = f.read()

# Check for timestamp (YYYY-MM-DD HH:MM:SS format)
assert any(char.isdigit() for char in content)

# Check for log level
assert "INFO" in content

# Check for logger name
assert "test_format" in content

# Check for message
assert "Format test message" in content
finally:
if os.path.exists(log_file):
os.unlink(log_file)

def test_integration_with_veta_components():
"""Test that veta components can use the logging system."""
from veta.respondent import Respondent
from veta.item import Item

# Setup logging
with tempfile.NamedTemporaryFile(mode='w', suffix='.log', delete=False) as f:
log_file = f.name

try:
setup_logging(
level='DEBUG',
log_file=log_file,
console_output=False
)

# Create veta components which should generate logs
respondent = Respondent(userid="test_user")
item = Item("I feel happy", "She looks sad")
respondent.add_item(item)

# Check that logs were generated
with open(log_file, 'r') as f:
content = f.read()
assert "respondent" in content.lower()
assert "item" in content.lower()

finally:
if os.path.exists(log_file):
os.unlink(log_file)

if __name__ == "__main__":
pytest.main([__file__, "-v"])
21 changes: 21 additions & 0 deletions veta/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""
Veta - A Python package for LEAS (Levels of Emotional Awareness Scale) analysis.
"""

from .logger import get_logger, setup_logging
from .survey import Survey
from .respondent import Respondent
from .item import Item
from .wordlist import Wordlist
from .auto_self_other_item import attempt_auto_self_other

__version__ = "1.0.0"
__all__ = [
"Survey",
"Respondent",
"Item",
"Wordlist",
"attempt_auto_self_other",
"get_logger",
"setup_logging"
]
Loading