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
2 changes: 1 addition & 1 deletion .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"]

steps:
- uses: actions/checkout@v4
Expand Down
7 changes: 0 additions & 7 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,8 @@
"cchardet",
]

test_deps = [
# Test timeouts
"wrapt-timeout-decorator",
]

extras = {
'speed': speed_deps,
'test': test_deps,
}

# Adapted from https://github.com/pypa/pip/blob/master/setup.py
Expand Down Expand Up @@ -54,7 +48,6 @@ def find_version(*file_paths):
"lxml-html-clean; python_version < '3.11'",
"cssselect"
],
tests_require=test_deps,
extras_require=extras,
classifiers=[
"Environment :: Web Environment",
Expand Down
30 changes: 28 additions & 2 deletions tests/test_article_only.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,34 @@
import os
import time
import unittest

from readability import Document
from wrapt_timeout_decorator import *
from functools import wraps


class TimeoutException(Exception):
"""Exception raised when a function exceeds its time limit."""
pass


def timeout(seconds):
"""Decorator to enforce a timeout on function execution."""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
elapsed_time = end_time - start_time
if elapsed_time > seconds:
raise TimeoutException(
f"Function '{func.__name__}' exceeded time limit of {seconds} seconds "
f"with an execution time of {elapsed_time:.4f} seconds"
)
return result
return wrapper
return decorator


SAMPLES = os.path.join(os.path.dirname(__file__), "samples")

Expand Down Expand Up @@ -100,7 +126,7 @@ def test_correct_cleanup(self):
assert not "aside" in s

# Many spaces make some regexes run forever
@timeout(3, use_signals=False)
@timeout(3)
def test_many_repeated_spaces(self):
long_space = " " * 1000000
sample = "<html><body><p>foo" + long_space + "</p></body></html>"
Expand Down
Loading