Path: blob/trunk/py/selenium/webdriver/common/print_page_options.py
4054 views
# Licensed to the Software Freedom Conservancy (SFC) under one1# or more contributor license agreements. See the NOTICE file2# distributed with this work for additional information3# regarding copyright ownership. The SFC licenses this file4# to you under the Apache License, Version 2.0 (the5# "License"); you may not use this file except in compliance6# with the License. You may obtain a copy of the License at7#8# http://www.apache.org/licenses/LICENSE-2.09#10# Unless required by applicable law or agreed to in writing,11# software distributed under the License is distributed on an12# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY13# KIND, either express or implied. See the License for the14# specific language governing permissions and limitations15# under the License.161718from typing import TYPE_CHECKING1920if TYPE_CHECKING:21from typing import Literal, TypedDict2223Orientation = Literal["portrait", "landscape"]2425class _MarginOpts(TypedDict, total=False):26left: float27right: float28top: float29bottom: float3031class _PageOpts(TypedDict, total=False):32width: float33height: float3435class _PrintOpts(TypedDict, total=False):36margin: _MarginOpts37page: _PageOpts38background: bool39orientation: Orientation40scale: float41shrinkToFit: bool42pageRanges: list[str]4344else:45from typing import Any4647Orientation = str48_MarginOpts = _PageOpts = _PrintOpts = dict[str, Any]495051class _PageSettingsDescriptor:52"""Descriptor which validates `height` and 'width' of page."""5354def __init__(self, name):55self.name = name5657def __get__(self, obj, cls) -> float | None:58return obj._page.get(self.name, None)5960def __set__(self, obj, value) -> None:61getattr(obj, "_validate_num_property")(self.name, value)62obj._page[self.name] = value63obj._print_options["page"] = obj._page646566class _MarginSettingsDescriptor:67"""Descriptor which validates below attributes.6869- top70- bottom71- left72- right73"""7475def __init__(self, name):76self.name = name7778def __get__(self, obj, cls) -> float | None:79return obj._margin.get(self.name, None)8081def __set__(self, obj, value) -> None:82getattr(obj, "_validate_num_property")(f"Margin {self.name}", value)83obj._margin[self.name] = value84obj._print_options["margin"] = obj._margin858687class _ScaleDescriptor:88"""Scale descriptor which validates scale."""8990def __init__(self, name):91self.name = name9293def __get__(self, obj, cls) -> float | None:94return obj._print_options.get(self.name)9596def __set__(self, obj, value) -> None:97getattr(obj, "_validate_num_property")(self.name, value)98if value < 0.1 or value > 2:99raise ValueError("Value of scale should be between 0.1 and 2")100obj._print_options[self.name] = value101102103class _PageOrientationDescriptor:104"""PageOrientation descriptor which validates orientation of page."""105106ORIENTATION_VALUES = ["portrait", "landscape"]107108def __init__(self, name):109self.name = name110111def __get__(self, obj, cls) -> Orientation | None:112return obj._print_options.get(self.name, None)113114def __set__(self, obj, value) -> None:115if value not in self.ORIENTATION_VALUES:116raise ValueError(f"Orientation value must be one of {self.ORIENTATION_VALUES}")117obj._print_options[self.name] = value118119120class _ValidateTypeDescriptor:121"""Base Class Descriptor which validates type of any subclass attribute."""122123def __init__(self, name, expected_type: type):124self.name = name125self.expected_type = expected_type126127def __get__(self, obj, cls):128return obj._print_options.get(self.name, None)129130def __set__(self, obj, value) -> None:131if not isinstance(value, self.expected_type):132raise ValueError(f"{self.name} should be of type {self.expected_type.__name__}")133obj._print_options[self.name] = value134135136class _ValidateBackGround(_ValidateTypeDescriptor):137"""Expected type of background attribute."""138139def __init__(self, name):140super().__init__(name, bool)141142143class _ValidateShrinkToFit(_ValidateTypeDescriptor):144"""Expected type of shrink to fit attribute."""145146def __init__(self, name):147super().__init__(name, bool)148149150class _ValidatePageRanges(_ValidateTypeDescriptor):151"""Expected type of page ranges attribute."""152153def __init__(self, name):154super().__init__(name, list)155156157class PrintOptions:158page_height = _PageSettingsDescriptor("height")159"""Gets and Sets page_height:160161Usage:162- Get: `self.page_height`163- Set: `self.page_height = value`164165Args:166value: float value for page height.167168Returns:169- Get: Optional[float]170- Set: None171"""172173page_width = _PageSettingsDescriptor("width")174"""Gets and Sets page_width:175176Usage:177- Get: `self.page_width`178- Set: `self.page_width = value`179180Args:181value: float value for page width.182183Returns:184- Get: Optional[float]185- Set: None186"""187188margin_top = _MarginSettingsDescriptor("top")189"""Gets and Sets margin_top:190191Usage:192- Get: `self.margin_top`193- Set: `self.margin_top = value`194195Args:196value: float value for top margin.197198Returns:199- Get: Optional[float]200- Set: None201"""202203margin_bottom = _MarginSettingsDescriptor("bottom")204"""Gets and Sets margin_bottom:205206Usage:207- Get: `self.margin_bottom`208- Set: `self.margin_bottom = value`209210Args:211value: float value for bottom margin.212213Returns:214- Get: Optional[float]215- Set: None216"""217218margin_left = _MarginSettingsDescriptor("left")219"""Gets and Sets margin_left:220221Usage:222- Get: `self.margin_left`223- Set: `self.margin_left = value`224225Args:226value: float value for left margin.227228Returns:229- Get: Optional[float]230- Set: None231"""232233margin_right = _MarginSettingsDescriptor("right")234"""Gets and Sets margin_right:235236Usage:237- Get: `self.margin_right`238- Set: `self.margin_right = value`239240Args:241value: float value for right margin.242243Returns:244- Get: Optional[float]245- Set: None246"""247248scale = _ScaleDescriptor("scale")249"""Gets and Sets scale:250251Usage:252- Get: `self.scale`253- Set: `self.scale = value`254255Args:256value: float value for scale (between 0.1 and 2).257258Returns:259- Get: Optional[float]260- Set: None261"""262263orientation = _PageOrientationDescriptor("orientation")264"""Gets and Sets orientation:265266Usage:267- Get: `self.orientation`268- Set: `self.orientation = value`269270Args:271value: Orientation value ("portrait" or "landscape").272273Returns:274- Get: Optional[Orientation]275- Set: None276"""277278background = _ValidateBackGround("background")279"""Gets and Sets background:280281Usage:282- Get: `self.background`283- Set: `self.background = value`284285Args:286value: bool value for background printing.287288Returns:289- Get: Optional[bool]290- Set: None291"""292293shrink_to_fit = _ValidateShrinkToFit("shrinkToFit")294"""Gets and Sets shrink_to_fit:295296Usage:297- Get: `self.shrink_to_fit`298- Set: `self.shrink_to_fit = value`299300Args:301value: bool value for shrink to fit.302303Returns:304- Get: Optional[bool]305- Set: None306"""307308page_ranges = _ValidatePageRanges("pageRanges")309"""Gets and Sets page_ranges:310311Usage:312- Get: `self.page_ranges`313- Set: `self.page_ranges = value`314315Args:316value: list of page range strings.317318Returns:319- Get: Optional[List[str]]320- Set: None321"""322# Reference for predefined page size constants: https://www.agooddaytoprint.com/page/paper-size-chart-faq323A4 = {"height": 29.7, "width": 21.0} # size in cm324LEGAL = {"height": 35.56, "width": 21.59} # size in cm325LETTER = {"height": 27.94, "width": 21.59} # size in cm326TABLOID = {"height": 43.18, "width": 27.94} # size in cm327328def __init__(self) -> None:329self._print_options: _PrintOpts = {}330self._page: _PageOpts = {331"height": PrintOptions.A4["height"],332"width": PrintOptions.A4["width"],333} # Default page size set to A4334self._margin: _MarginOpts = {}335336def to_dict(self) -> _PrintOpts:337"""Returns a hash of print options configured."""338return self._print_options339340def set_page_size(self, page_size: dict) -> None:341"""Sets the page size to predefined or custom dimensions.342343Args:344page_size: A dictionary containing 'height' and 'width' keys with345respective values in cm.346347Example:348self.set_page_size(PageSize.A4) # A4 predefined size349self.set_page_size({"height": 15.0, "width": 20.0}) # Custom size350"""351self._validate_num_property("height", page_size["height"])352self._validate_num_property("width", page_size["width"])353self._page["height"] = page_size["height"]354self._page["width"] = page_size["width"]355self._print_options["page"] = self._page356357def _validate_num_property(self, property_name: str, value: float) -> None:358"""Helper function to validate some of the properties."""359if not isinstance(value, (int, float)):360raise ValueError(f"{property_name} should be an integer or a float")361362if value < 0:363raise ValueError(f"{property_name} cannot be less than 0")364365366