Python supercharged for fastai development
56
Comprehensive testing utilities with detailed error reporting, specialized assertion helpers for different data types, and utilities for testing exceptions and warnings. Designed for use in notebooks and scripts with clear, informative error messages.
Essential testing functions that provide clear error messages and handle various data types including arrays, iterables, and custom objects.
def test_eq(a, b):
"""
Test that a equals b with detailed error reporting.
Uses fastcore's enhanced equality checking that handles:
- numpy arrays with array_equal
- pandas DataFrames with df_equal
- nested structures with proper comparison
- Custom objects with appropriate equality methods
Parameters:
- a: First value to compare
- b: Second value to compare
Raises:
AssertionError: If values are not equal, with detailed comparison
"""
def test_eq_type(a, b):
"""
Test that a equals b and they are the same type.
Also recursively checks types for list/tuple elements.
Parameters:
- a: First value to compare
- b: Second value to compare
Raises:
AssertionError: If values differ or types don't match
"""
def test_ne(a, b):
"""
Test that a is not equal to b.
Parameters:
- a: First value to compare
- b: Second value to compare
Raises:
AssertionError: If values are equal
"""
def test_is(a, b):
"""
Test that a is b (identity check, not equality).
Parameters:
- a: First object
- b: Second object
Raises:
AssertionError: If objects are not identical
"""
def test_close(a, b, eps=1e-5):
"""
Test that a is within eps of b for numerical comparisons.
Handles:
- Scalar numbers
- numpy arrays (element-wise comparison)
- Iterables (element-wise comparison)
Parameters:
- a: First numerical value
- b: Second numerical value
- eps: float, tolerance for comparison (default: 1e-5)
Raises:
AssertionError: If values differ by more than eps
"""
def is_close(a, b, eps=1e-5):
"""
Check if a is within eps of b without raising exception.
Parameters:
- a: First numerical value
- b: Second numerical value
- eps: float, tolerance for comparison
Returns:
bool: True if values are within tolerance
"""Utilities for testing that code raises expected exceptions with proper error messages.
def test_fail(f, msg='', contains='', exc=Exception, args=None, kwargs=None):
"""
Test that function f raises specified exception with optional message checking.
Parameters:
- f: Function to test
- msg: str, additional message for assertion failure
- contains: str, substring that should be in exception message
- exc: Exception class expected to be raised
- args: list, arguments to pass to f
- kwargs: dict, keyword arguments to pass to f
Raises:
AssertionError: If wrong exception raised or none at all
"""
class ExceptionExpected:
"""
Context manager for testing expected exceptions with regex matching.
Parameters:
- ex: Exception class to expect (default: Exception)
- regex: str, regex pattern to match in exception message
Usage:
with ExceptionExpected(ValueError, "invalid.*format"):
risky_operation()
"""
def __init__(self, ex=Exception, regex=''): ...
def __enter__(self): ...
def __exit__(self, type, value, traceback): ...
# Convenience instance for common use
exception = ExceptionExpected()Testing functions for specific scenarios like output checking, warnings, and matplotlib figures.
def test_stdout(f, exp, regex=False):
"""
Test that function f prints expected output to stdout.
Parameters:
- f: Function to execute
- exp: str, expected output (without newline)
- regex: bool, treat exp as regex pattern if True
Raises:
AssertionError: If output doesn't match expectation
"""
def test_warns(f, show=False):
"""
Test that function f produces warnings.
Parameters:
- f: Function to execute
- show: bool, print warning details if True
Raises:
AssertionError: If no warnings are raised
"""
def test_fig_exists(ax):
"""
Test that a matplotlib figure exists and has content.
Parameters:
- ax: matplotlib axes object
Raises:
AssertionError: If no figure or empty figure
"""
def test_shuffled(a, b):
"""
Test that two sequences contain the same elements but in different order.
Parameters:
- a: First sequence
- b: Second sequence
Raises:
AssertionError: If sequences are identical or contain different elements
"""Core comparison and testing utilities used by the testing framework.
def test(a, b, cmp, cname=None):
"""
Generic test function using custom comparison function.
Parameters:
- a: First value
- b: Second value
- cmp: Comparison function that returns bool
- cname: str, name of comparison for error messages
Raises:
AssertionError: If cmp(a, b) returns False
"""
def nequals(a, b):
"""
Check if two values are not equal using fastcore's equality checking.
Parameters:
- a: First value
- b: Second value
Returns:
bool: True if values are not equal
"""Pre-defined test resources for common testing scenarios.
TEST_IMAGE = 'images/puppy.jpg'
"""str: Path to test image file for image processing tests."""
TEST_IMAGE_BW = 'images/mnist3.png'
"""str: Path to black and white test image for grayscale processing tests."""from fastcore.test import test_eq, test_ne, test_eq_type
# Basic equality testing
test_eq([1, 2, 3], [1, 2, 3]) # Passes
test_eq("hello", "hello") # Passes
# Type checking
test_eq_type([1, 2], [1, 2]) # Passes - same values and types
test_eq_type([1, 2], (1, 2)) # Fails - different types
# Inequality testing
test_ne([1, 2], [1, 3]) # Passes
test_ne("hello", "world") # Passesfrom fastcore.test import test_close, is_close
import numpy as np
# Floating point comparisons
test_close(3.14159, 3.14160, eps=1e-4) # Passes
test_close(1.0, 1.0001, eps=1e-3) # Passes
# Array comparisons
arr1 = np.array([1.0, 2.0, 3.0])
arr2 = np.array([1.0001, 2.0001, 3.0001])
test_close(arr1, arr2, eps=1e-3) # Passes
# Check without raising exception
close = is_close(3.14, 3.15, eps=0.1) # Returns Truefrom fastcore.test import test_fail, ExceptionExpected, exception
# Test specific exception type
test_fail(lambda: 1/0, exc=ZeroDivisionError)
# Test exception with message content
test_fail(lambda: int("abc"),
contains="invalid literal",
exc=ValueError)
# Using context manager
with ExceptionExpected(ValueError, "invalid.*literal"):
int("not_a_number")
# Using convenience instance
with exception: # Expects any Exception
raise RuntimeError("Something went wrong")from fastcore.test import test_stdout, test_warns
# Test printed output
def hello_world():
print("Hello, World!")
test_stdout(hello_world, "Hello, World!")
# Test with regex
def print_number():
print("Number: 42")
test_stdout(print_number, r"Number: \d+", regex=True)
# Test warnings
def deprecated_function():
import warnings
warnings.warn("This function is deprecated", DeprecationWarning)
test_warns(deprecated_function) # Passes if warning is raisedfrom fastcore.test import test_eq, test_shuffled
import numpy as np
import pandas as pd
# Testing pandas DataFrames
df1 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
df2 = pd.DataFrame({'A': [1, 2], 'B': [3, 4]})
test_eq(df1, df2) # Uses DataFrame-specific equality
# Testing numpy arrays
arr1 = np.array([[1, 2], [3, 4]])
arr2 = np.array([[1, 2], [3, 4]])
test_eq(arr1, arr2) # Uses array-specific equality
# Test shuffled sequences
original = [1, 2, 3, 4, 5]
shuffled = [3, 1, 5, 2, 4]
test_shuffled(original, shuffled) # Passes - same elements, different orderfrom fastcore.test import test_fig_exists
import matplotlib.pyplot as plt
# Create a plot
fig, ax = plt.subplots()
ax.plot([1, 2, 3], [1, 4, 9])
# Test that figure has content
test_fig_exists(ax) # Passes - figure has plot datafrom fastcore.test import test
# Custom comparison function
def approximately_equal(a, b):
return abs(a - b) < 0.1
# Use custom test
test(3.14, 3.15, approximately_equal, "approximately equal")
# Testing custom objects
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __eq__(self, other):
return self.name == other.name and self.age == other.age
person1 = Person("Alice", 30)
person2 = Person("Alice", 30)
test_eq(person1, person2) # Uses custom __eq__ methodInstall with Tessl CLI
npx tessl i tessl/pypi-fastcoredocs
evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10