Skip to content

Edge Cases & Discoveries

This section documents interesting edge cases, unexpected behaviors, and discoveries made while testing Python's standard library.

๐Ÿ” Overview

Through comprehensive testing with pytest and Hypothesis, we've discovered various edge cases that are important for:

  • Transpiler Validation: Ensuring Depyler handles all stdlib behaviors correctly
  • Developer Education: Understanding subtle Python behaviors
  • Bug Prevention: Avoiding common pitfalls

๐Ÿ“‹ Categories

Data Type Edge Cases

  • JSON Encoding: Unicode handling, special characters, NaN/Infinity
  • Datetime: Timezone edge cases, leap seconds, DST transitions
  • Decimal: Precision limits, rounding behaviors
  • Fractions: Overflow conditions, normalization

Collection Behaviors

  • Collections: OrderedDict ordering guarantees
  • Itertools: Infinite iterator handling
  • Copy: Deep copy circular reference handling

System Interfaces

  • OS/Path: Cross-platform path separators
  • Sys: Platform-specific behaviors
  • IO: Buffering edge cases

๐Ÿ› Notable Discoveries

1. JSON NaN Handling

Non-Standard Behavior

Python's json.dumps() produces non-standard JSON for NaN and Infinity values:

>>> import json
>>> json.dumps({"value": float('nan')})
'{"value": NaN}'  # Not valid JSON!

Workaround: Use allow_nan=False parameter

2. Datetime Timezone Arithmetic

DST Transitions

Arithmetic on timezone-aware datetimes can produce unexpected results during DST transitions:

# Adding 24 hours != adding 1 day during DST change

3. Decimal Context

Global State

Decimal module uses global context that can affect test isolation:

import decimal
# Context changes persist across tests!
decimal.getcontext().prec = 2

4. Pathlib vs os.path

Behavior Differences

pathlib and os.path handle empty paths differently:

>>> from pathlib import Path
>>> import os.path
>>> Path('').absolute()  # Uses current directory
>>> os.path.abspath('')  # Also uses current directory

๐Ÿ“Š Edge Case Statistics

Module Edge Cases Found Property Tests Mutation Score
json 6 1 95%
datetime 8 1 92%
decimal 13 0 88%
collections 7 0 94%
itertools 9 0 96%

๐Ÿงช Testing Methodology

Property-Based Testing

We use Hypothesis to automatically discover edge cases:

from hypothesis import given, strategies as st

@given(st.text())
def test_json_roundtrip(data):
    """Any text should survive JSON encode/decode."""
    encoded = json.dumps(data)
    decoded = json.loads(encoded)
    assert decoded == data

Mutation Testing

Ensures our tests actually verify behavior:

# Example mutation testing
mutmut run --paths-to-mutate=tests/

Fuzzing

Discovers unexpected inputs:

# Hypothesis fuzzing
@given(st.binary())
def test_base64_decode_robustness(data):
    """Test base64 with random binary data."""
    try:
        encoded = base64.b64encode(data)
        decoded = base64.b64decode(encoded)
        assert decoded == data
    except Exception as e:
        # Document unexpected exceptions
        pass

๐ŸŽฏ Contributing Edge Cases

Found an interesting edge case? Please contribute!

  1. Create a test demonstrating the behavior
  2. Document the edge case
  3. Explain implications for transpilation
  4. Suggest workarounds if needed

๐Ÿ“š Resources