added tests for images
Python CI / test (push) Failing after 43s

Added loading funcs for images
This commit is contained in:
2025-06-07 18:23:06 +02:00
parent ec4070a083
commit 4029fdff96
2 changed files with 456 additions and 0 deletions
+159
View File
@@ -1,5 +1,10 @@
from typing import List, Iterator, Tuple, Dict, Optional, Union, Any
from enum import Enum
import os
import tempfile
import urllib.request
import urllib.parse
from PIL import Image as PILImage
from .inline import Word, FormattedSpan
@@ -1219,6 +1224,160 @@ class Image(Block):
height = max_height
return (width, height)
def _is_url(self, source: str) -> bool:
"""
Check if the source is a URL.
Args:
source: The source string to check
Returns:
True if the source appears to be a URL, False otherwise
"""
parsed = urllib.parse.urlparse(source)
return bool(parsed.scheme and parsed.netloc)
def _download_to_temp(self, url: str) -> str:
"""
Download an image from a URL to a temporary file.
Args:
url: The URL to download from
Returns:
Path to the temporary file
Raises:
urllib.error.URLError: If the download fails
"""
# Create a temporary file
temp_fd, temp_path = tempfile.mkstemp(suffix='.tmp')
try:
# Download the image
with urllib.request.urlopen(url) as response:
# Write the response data to the temporary file
with os.fdopen(temp_fd, 'wb') as temp_file:
temp_file.write(response.read())
return temp_path
except:
# Clean up the temporary file if download fails
try:
os.close(temp_fd)
except:
pass
try:
os.unlink(temp_path)
except:
pass
raise
def load_image_data(self, auto_update_dimensions: bool = True) -> Tuple[Optional[str], Optional[PILImage.Image]]:
"""
Load image data using PIL, handling both local files and URLs.
Args:
auto_update_dimensions: If True, automatically update width and height from the loaded image
Returns:
Tuple of (file_path, PIL_Image_object). For URLs, file_path is the temporary file path.
Returns (None, None) if loading fails.
"""
if not self._source:
return None, None
file_path = None
temp_file = None
try:
if self._is_url(self._source):
# Download to temporary file
temp_file = self._download_to_temp(self._source)
file_path = temp_file
else:
# Use local file path
file_path = self._source
# Open with PIL
with PILImage.open(file_path) as img:
# Load the image data
img.load()
# Update dimensions if requested
if auto_update_dimensions:
self._width, self._height = img.size
# Return a copy to avoid issues with the context manager
return file_path, img.copy()
except Exception as e:
# Clean up temporary file on error
if temp_file and os.path.exists(temp_file):
try:
os.unlink(temp_file)
except:
pass
return None, None
def get_image_info(self) -> Dict[str, Any]:
"""
Get detailed information about the image using PIL.
Returns:
Dictionary containing image information including format, mode, size, etc.
Returns empty dict if image cannot be loaded.
"""
file_path, img = self.load_image_data(auto_update_dimensions=False)
if img is None:
return {}
# Try to determine format from the image, file extension, or source
img_format = img.format
if img_format is None:
# Try to determine format from file extension
format_map = {
'.jpg': 'JPEG',
'.jpeg': 'JPEG',
'.png': 'PNG',
'.gif': 'GIF',
'.bmp': 'BMP',
'.tiff': 'TIFF',
'.tif': 'TIFF'
}
# First try the actual file path if available
if file_path:
ext = os.path.splitext(file_path)[1].lower()
img_format = format_map.get(ext)
# If still no format and we have a URL source, try the original URL
if img_format is None and self._is_url(self._source):
ext = os.path.splitext(urllib.parse.urlparse(self._source).path)[1].lower()
img_format = format_map.get(ext)
info = {
'format': img_format,
'mode': img.mode,
'size': img.size,
'width': img.width,
'height': img.height,
}
# Add additional info if available
if hasattr(img, 'info'):
info['info'] = img.info
# Clean up temporary file if it was created
if file_path and self._is_url(self._source):
try:
os.unlink(file_path)
except:
pass
return info
class HorizontalRule(Block):