Additional changes.
Python CI / test (push) Failing after 1m35s

This commit is contained in:
2025-06-06 20:54:33 +02:00
parent f7ad69f9ec
commit c0c366e9f4
13 changed files with 2661 additions and 325 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
from .block import Block, BlockType, Parapgraph, Heading, HeadingLevel, Quote, CodeBlock
from .block import Block, BlockType, Paragraph, Heading, HeadingLevel, Quote, CodeBlock
from .block import HList, ListItem, ListStyle, Table, TableRow, TableCell
from .block import HorizontalRule, LineBreak, Image
from .inline import Word, FormattedSpan
File diff suppressed because it is too large Load Diff
+119 -8
View File
@@ -1,7 +1,7 @@
from __future__ import annotations
from typing import List, Dict, Optional, Tuple, Union, Any
from enum import Enum
from .block import Block, BlockType, Heading, HeadingLevel, Parapgraph
from .block import Block, BlockType, Heading, HeadingLevel, Paragraph
from .functional import Link, Button, Form
from .inline import Word, FormattedSpan
@@ -27,13 +27,14 @@ class Document:
This class manages the logical structure of the document without rendering concerns.
"""
def __init__(self, title: Optional[str] = None, language: str = "en-US"):
def __init__(self, title: Optional[str] = None, language: str = "en-US", default_style=None):
"""
Initialize a new document.
Args:
title: The document title
language: The document language code
default_style: Optional default style for child blocks
"""
self._blocks: List[Block] = []
self._metadata: Dict[MetadataType, Any] = {}
@@ -41,6 +42,7 @@ class Document:
self._resources: Dict[str, Any] = {} # External resources like images
self._stylesheets: List[Dict[str, Any]] = [] # CSS stylesheets
self._scripts: List[str] = [] # JavaScript code
self._default_style = default_style
# Set basic metadata
if title:
@@ -52,6 +54,16 @@ class Document:
"""Get the top-level blocks in this document"""
return self._blocks
@property
def default_style(self):
"""Get the default style for this document"""
return self._default_style
@default_style.setter
def default_style(self, style):
"""Set the default style for this document"""
self._default_style = style
def add_block(self, block: Block):
"""
Add a block to this document.
@@ -61,6 +73,55 @@ class Document:
"""
self._blocks.append(block)
def create_paragraph(self, style=None) -> Paragraph:
"""
Create a new paragraph and add it to this document.
Args:
style: Optional style override. If None, inherits from document
Returns:
The newly created Paragraph object
"""
if style is None:
style = self._default_style
paragraph = Paragraph(style)
self.add_block(paragraph)
return paragraph
def create_heading(self, level: HeadingLevel = HeadingLevel.H1, style=None) -> Heading:
"""
Create a new heading and add it to this document.
Args:
level: The heading level
style: Optional style override. If None, inherits from document
Returns:
The newly created Heading object
"""
if style is None:
style = self._default_style
heading = Heading(level, style)
self.add_block(heading)
return heading
def create_chapter(self, title: Optional[str] = None, level: int = 1, style=None) -> 'Chapter':
"""
Create a new chapter with inherited style.
Args:
title: The chapter title
level: The chapter level
style: Optional style override. If None, inherits from document
Returns:
The newly created Chapter object
"""
if style is None:
style = self._default_style
return Chapter(title, level, style)
def set_metadata(self, meta_type: MetadataType, value: Any):
"""
Set a metadata value.
@@ -229,18 +290,20 @@ class Chapter:
A chapter contains a sequence of blocks and has metadata.
"""
def __init__(self, title: Optional[str] = None, level: int = 1):
def __init__(self, title: Optional[str] = None, level: int = 1, style=None):
"""
Initialize a new chapter.
Args:
title: The chapter title
level: The chapter level (1 = top level, 2 = subsection, etc.)
style: Optional default style for child blocks
"""
self._title = title
self._level = level
self._blocks: List[Block] = []
self._metadata: Dict[str, Any] = {}
self._style = style
@property
def title(self) -> Optional[str]:
@@ -262,6 +325,16 @@ class Chapter:
"""Get the blocks in this chapter"""
return self._blocks
@property
def style(self):
"""Get the default style for this chapter"""
return self._style
@style.setter
def style(self, style):
"""Set the default style for this chapter"""
self._style = style
def add_block(self, block: Block):
"""
Add a block to this chapter.
@@ -271,6 +344,39 @@ class Chapter:
"""
self._blocks.append(block)
def create_paragraph(self, style=None) -> Paragraph:
"""
Create a new paragraph and add it to this chapter.
Args:
style: Optional style override. If None, inherits from chapter
Returns:
The newly created Paragraph object
"""
if style is None:
style = self._style
paragraph = Paragraph(style)
self.add_block(paragraph)
return paragraph
def create_heading(self, level: HeadingLevel = HeadingLevel.H1, style=None) -> Heading:
"""
Create a new heading and add it to this chapter.
Args:
level: The heading level
style: Optional style override. If None, inherits from chapter
Returns:
The newly created Heading object
"""
if style is None:
style = self._style
heading = Heading(level, style)
self.add_block(heading)
return heading
def set_metadata(self, key: str, value: Any):
"""
Set a metadata value.
@@ -300,7 +406,8 @@ class Book(Document):
A book is a document that contains chapters.
"""
def __init__(self, title: Optional[str] = None, author: Optional[str] = None, language: str = "en-US"):
def __init__(self, title: Optional[str] = None, author: Optional[str] = None,
language: str = "en-US", default_style=None):
"""
Initialize a new book.
@@ -308,8 +415,9 @@ class Book(Document):
title: The book title
author: The book author
language: The book language code
default_style: Optional default style for child chapters and blocks
"""
super().__init__(title, language)
super().__init__(title, language, default_style)
self._chapters: List[Chapter] = []
if author:
@@ -329,18 +437,21 @@ class Book(Document):
"""
self._chapters.append(chapter)
def create_chapter(self, title: Optional[str] = None, level: int = 1) -> Chapter:
def create_chapter(self, title: Optional[str] = None, level: int = 1, style=None) -> Chapter:
"""
Create and add a new chapter.
Create and add a new chapter with inherited style.
Args:
title: The chapter title
level: The chapter level
style: Optional style override. If None, inherits from book
Returns:
The new chapter
"""
chapter = Chapter(title, level)
if style is None:
style = self._default_style
chapter = Chapter(title, level, style)
self.add_chapter(chapter)
return chapter
+124
View File
@@ -27,6 +27,91 @@ class Word:
self._previous = previous
self._next = None
self._hyphenated_parts = None # Will store hyphenated parts if word is hyphenated
@classmethod
def create_and_add_to(cls, text: str, container, style: Optional[Font] = None,
background=None) -> 'Word':
"""
Create a new Word and add it to a container, inheriting style and language
from the container if not explicitly provided.
This method provides a convenient way to create words that automatically
inherit styling from their container (Paragraph, FormattedSpan, etc.)
without copying string values - using object references instead.
Args:
text: The text content of the word
container: The container to add the word to (must have add_word method and style property)
style: Optional Font style override. If None, inherits from container
background: Optional background color override. If None, inherits from container
Returns:
The newly created Word object
Raises:
AttributeError: If the container doesn't have the required add_word method or style property
"""
# Inherit style from container if not provided
if style is None:
if hasattr(container, 'style'):
style = container.style
else:
raise AttributeError(f"Container {type(container).__name__} must have a 'style' property")
# Inherit background from container if not provided
if background is None and hasattr(container, 'background'):
background = container.background
# Determine the previous word for proper linking
previous = None
if hasattr(container, '_words') and container._words:
# Container has a _words list (like FormattedSpan)
previous = container._words[-1]
elif hasattr(container, 'words'):
# Container has a words() method (like Paragraph)
try:
# Get the last word from the iterator
for _, word in container.words():
previous = word
except (StopIteration, TypeError):
previous = None
# Create the new word
word = cls(text, style, background, previous)
# Link the previous word to this new one
if previous:
previous.add_next(word)
# Add the word to the container
if hasattr(container, 'add_word'):
# Check if add_word expects a Word object or text string
import inspect
sig = inspect.signature(container.add_word)
params = list(sig.parameters.keys())
if len(params) > 0:
# Peek at the parameter name to guess the expected type
param_name = params[0]
if param_name in ['word', 'word_obj', 'word_object']:
# Expects a Word object
container.add_word(word)
else:
# Might expect text string (like FormattedSpan.add_word)
# In this case, we can't use the container's add_word as it would create
# a duplicate Word. We need to add directly to the container's word list.
if hasattr(container, '_words'):
container._words.append(word)
else:
# Fallback: try calling with the Word object anyway
container.add_word(word)
else:
# No parameters, shouldn't happen with add_word methods
container.add_word(word)
else:
raise AttributeError(f"Container {type(container).__name__} must have an 'add_word' method")
return word
@property
def text(self) -> str:
@@ -167,6 +252,45 @@ class FormattedSpan:
self._background = background if background else style.background
self._words: List[Word] = []
@classmethod
def create_and_add_to(cls, container, style: Optional[Font] = None, background=None) -> 'FormattedSpan':
"""
Create a new FormattedSpan and add it to a container, inheriting style from
the container if not explicitly provided.
Args:
container: The container to add the span to (must have add_span method and style property)
style: Optional Font style override. If None, inherits from container
background: Optional background color override
Returns:
The newly created FormattedSpan object
Raises:
AttributeError: If the container doesn't have the required add_span method or style property
"""
# Inherit style from container if not provided
if style is None:
if hasattr(container, 'style'):
style = container.style
else:
raise AttributeError(f"Container {type(container).__name__} must have a 'style' property")
# Inherit background from container if not provided
if background is None and hasattr(container, 'background'):
background = container.background
# Create the new span
span = cls(style, background)
# Add the span to the container
if hasattr(container, 'add_span'):
container.add_span(span)
else:
raise AttributeError(f"Container {type(container).__name__} must have an 'add_span' method")
return span
@property
def style(self) -> Font:
"""Get the font style of this span"""
+1 -1
View File
@@ -27,7 +27,7 @@ def main():
parser.add_argument('epub_file', help='Path to EPUB file')
parser.add_argument('--output-dir', '-o', default='output', help='Output directory for rendered pages')
parser.add_argument('--width', '-w', type=int, default=800, help='Page width')
parser.add_argument('--height', '-h', type=int, default=1000, help='Page height')
parser.add_argument('--height', '-y', type=int, default=1000, help='Page height')
parser.add_argument('--margin', '-m', type=int, default=50, help='Page margin')
parser.add_argument('--max-pages', '-p', type=int, default=10, help='Maximum number of pages to render')
args = parser.parse_args()
+86
View File
@@ -0,0 +1,86 @@
#!/usr/bin/env python3
"""
Simple EPUB test script to isolate the issue.
"""
import sys
from pathlib import Path
# Add the parent directory to the path to import pyWebLayout
sys.path.append(str(Path(__file__).parent.parent.parent))
def test_epub_basic():
"""Test basic EPUB functionality without full HTML parsing."""
print("Testing basic EPUB components...")
try:
# Test basic document classes
from pyWebLayout.abstract.document import Document, Book, Chapter, MetadataType
print("✓ Document classes imported")
# Test creating a simple book
book = Book("Test Book", "Test Author")
chapter = book.create_chapter("Test Chapter")
print("✓ Book and chapter created")
return True
except Exception as e:
print(f"✗ Basic test failed: {e}")
import traceback
traceback.print_exc()
return False
def test_epub_file():
"""Test opening the EPUB file without full parsing."""
print("Testing EPUB file access...")
try:
import zipfile
import os
epub_path = "pg174-images-3.epub"
if not os.path.exists(epub_path):
print(f"✗ EPUB file not found: {epub_path}")
return False
with zipfile.ZipFile(epub_path, 'r') as zip_ref:
file_list = zip_ref.namelist()
print(f"✓ EPUB file opened, contains {len(file_list)} files")
# Look for key files
has_container = any('container.xml' in f for f in file_list)
has_opf = any('.opf' in f for f in file_list)
print(f"✓ Container file: {'found' if has_container else 'not found'}")
print(f"✓ Package file: {'found' if has_opf else 'not found'}")
return True
except Exception as e:
print(f"✗ EPUB file test failed: {e}")
import traceback
traceback.print_exc()
return False
def main():
print("Simple EPUB Test")
print("=" * 50)
# Test basic functionality
if not test_epub_basic():
return False
print()
# Test EPUB file access
if not test_epub_file():
return False
print()
print("All basic tests passed!")
return True
if __name__ == "__main__":
success = main()
sys.exit(0 if success else 1)
+5 -2
View File
@@ -370,7 +370,7 @@ class EPUBReader:
# Parse HTML and add blocks to chapter
base_url = os.path.dirname(path)
document = parse_html(html, base_url)
document = parse_html(html, base_url=base_url)
# Copy blocks to the chapter
for block in document.blocks:
@@ -381,8 +381,11 @@ class EPUBReader:
# Add an error message block
from pyWebLayout.abstract.block import Parapgraph
from pyWebLayout.abstract.inline import Word
from pyWebLayout.style import Font
error_para = Parapgraph()
error_para.add_word(Word(f"Error loading chapter: {str(e)}"))
# Create a default font style for the error message
default_font = Font()
error_para.add_word(Word(f"Error loading chapter: {str(e)}", default_font))
chapter.add_block(error_para)