Skip to content

Commit

Permalink
rfctr: improve typing
Browse files Browse the repository at this point in the history
  • Loading branch information
scanny committed May 1, 2024
1 parent e493474 commit f246fde
Show file tree
Hide file tree
Showing 32 changed files with 501 additions and 461 deletions.
17 changes: 9 additions & 8 deletions features/steps/coreprops.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from datetime import datetime, timedelta

from behave import given, then, when
from behave.runner import Context

from docx import Document
from docx.opc.coreprops import CoreProperties
Expand All @@ -13,25 +14,25 @@


@given("a document having known core properties")
def given_a_document_having_known_core_properties(context):
def given_a_document_having_known_core_properties(context: Context):
context.document = Document(test_docx("doc-coreprops"))


@given("a document having no core properties part")
def given_a_document_having_no_core_properties_part(context):
def given_a_document_having_no_core_properties_part(context: Context):
context.document = Document(test_docx("doc-no-coreprops"))


# when ====================================================


@when("I access the core properties object")
def when_I_access_the_core_properties_object(context):
def when_I_access_the_core_properties_object(context: Context):
context.document.core_properties


@when("I assign new values to the properties")
def when_I_assign_new_values_to_the_properties(context):
def when_I_assign_new_values_to_the_properties(context: Context):
context.propvals = (
("author", "Creator"),
("category", "Category"),
Expand All @@ -58,7 +59,7 @@ def when_I_assign_new_values_to_the_properties(context):


@then("a core properties part with default values is added")
def then_a_core_properties_part_with_default_values_is_added(context):
def then_a_core_properties_part_with_default_values_is_added(context: Context):
core_properties = context.document.core_properties
assert core_properties.title == "Word Document"
assert core_properties.last_modified_by == "python-docx"
Expand All @@ -71,14 +72,14 @@ def then_a_core_properties_part_with_default_values_is_added(context):


@then("I can access the core properties object")
def then_I_can_access_the_core_properties_object(context):
def then_I_can_access_the_core_properties_object(context: Context):
document = context.document
core_properties = document.core_properties
assert isinstance(core_properties, CoreProperties)


@then("the core property values match the known values")
def then_the_core_property_values_match_the_known_values(context):
def then_the_core_property_values_match_the_known_values(context: Context):
known_propvals = (
("author", "Steve Canny"),
("category", "Category"),
Expand Down Expand Up @@ -106,7 +107,7 @@ def then_the_core_property_values_match_the_known_values(context):


@then("the core property values match the new values")
def then_the_core_property_values_match_the_new_values(context):
def then_the_core_property_values_match_the_new_values(context: Context):
core_properties = context.document.core_properties
for name, expected_value in context.propvals:
value = getattr(core_properties, name)
Expand Down
11 changes: 0 additions & 11 deletions src/docx/enum/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +0,0 @@
"""Enumerations used in python-docx."""


class Enumeration:
@classmethod
def from_xml(cls, xml_val):
return cls._xml_to_idx[xml_val]

@classmethod
def to_xml(cls, enum_val):
return cls._idx_to_xml[enum_val]
2 changes: 1 addition & 1 deletion src/docx/image/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def height(self) -> Inches:
return Inches(self.px_height / self.vert_dpi)

def scaled_dimensions(
self, width: int | None = None, height: int | None = None
self, width: int | Length | None = None, height: int | Length | None = None
) -> Tuple[Length, Length]:
"""(cx, cy) pair representing scaled dimensions of this image.
Expand Down
33 changes: 21 additions & 12 deletions src/docx/opc/coreprops.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,53 @@
These are broadly-standardized attributes like author, last-modified, etc.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from docx.oxml.coreprops import CT_CoreProperties

if TYPE_CHECKING:
from docx.oxml.coreprops import CT_CoreProperties


class CoreProperties:
"""Corresponds to part named ``/docProps/core.xml``, containing the core document
properties for this document package."""

def __init__(self, element):
def __init__(self, element: CT_CoreProperties):
self._element = element

@property
def author(self):
return self._element.author_text

@author.setter
def author(self, value):
def author(self, value: str):
self._element.author_text = value

@property
def category(self):
return self._element.category_text

@category.setter
def category(self, value):
def category(self, value: str):
self._element.category_text = value

@property
def comments(self):
return self._element.comments_text

@comments.setter
def comments(self, value):
def comments(self, value: str):
self._element.comments_text = value

@property
def content_status(self):
return self._element.contentStatus_text

@content_status.setter
def content_status(self, value):
def content_status(self, value: str):
self._element.contentStatus_text = value

@property
Expand All @@ -56,31 +65,31 @@ def identifier(self):
return self._element.identifier_text

@identifier.setter
def identifier(self, value):
def identifier(self, value: str):
self._element.identifier_text = value

@property
def keywords(self):
return self._element.keywords_text

@keywords.setter
def keywords(self, value):
def keywords(self, value: str):
self._element.keywords_text = value

@property
def language(self):
return self._element.language_text

@language.setter
def language(self, value):
def language(self, value: str):
self._element.language_text = value

@property
def last_modified_by(self):
return self._element.lastModifiedBy_text

@last_modified_by.setter
def last_modified_by(self, value):
def last_modified_by(self, value: str):
self._element.lastModifiedBy_text = value

@property
Expand Down Expand Up @@ -112,21 +121,21 @@ def subject(self):
return self._element.subject_text

@subject.setter
def subject(self, value):
def subject(self, value: str):
self._element.subject_text = value

@property
def title(self):
return self._element.title_text

@title.setter
def title(self, value):
def title(self, value: str):
self._element.title_text = value

@property
def version(self):
return self._element.version_text

@version.setter
def version(self, value):
def version(self, value: str):
self._element.version_text = value
13 changes: 8 additions & 5 deletions src/docx/opc/oxml.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
deleted or only hold the package related custom element classes.
"""

from __future__ import annotations

from typing import cast

from lxml import etree

from docx.opc.constants import NAMESPACE as NS
Expand Down Expand Up @@ -138,7 +142,7 @@ class CT_Relationship(BaseOxmlElement):
target part."""

@staticmethod
def new(rId, reltype, target, target_mode=RTM.INTERNAL):
def new(rId: str, reltype: str, target: str, target_mode: str = RTM.INTERNAL):
"""Return a new ``<Relationship>`` element."""
xml = '<Relationship xmlns="%s"/>' % nsmap["pr"]
relationship = parse_xml(xml)
Expand Down Expand Up @@ -178,19 +182,18 @@ def target_mode(self):
class CT_Relationships(BaseOxmlElement):
"""``<Relationships>`` element, the root element in a .rels file."""

def add_rel(self, rId, reltype, target, is_external=False):
def add_rel(self, rId: str, reltype: str, target: str, is_external: bool = False):
"""Add a child ``<Relationship>`` element with attributes set according to
parameter values."""
target_mode = RTM.EXTERNAL if is_external else RTM.INTERNAL
relationship = CT_Relationship.new(rId, reltype, target, target_mode)
self.append(relationship)

@staticmethod
def new():
def new() -> CT_Relationships:
"""Return a new ``<Relationships>`` element."""
xml = '<Relationships xmlns="%s"/>' % nsmap["pr"]
relationships = parse_xml(xml)
return relationships
return cast(CT_Relationships, parse_xml(xml))

@property
def Relationship_lst(self):
Expand Down
18 changes: 11 additions & 7 deletions src/docx/opc/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from typing import IO, TYPE_CHECKING, Iterator
from typing import IO, TYPE_CHECKING, Iterator, cast

from docx.opc.constants import RELATIONSHIP_TYPE as RT
from docx.opc.packuri import PACKAGE_URI, PackURI
Expand All @@ -14,7 +14,9 @@
from docx.shared import lazyproperty

if TYPE_CHECKING:
from docx.opc.coreprops import CoreProperties
from docx.opc.part import Part
from docx.opc.rel import _Relationship # pyright: ignore[reportPrivateUsage]


class OpcPackage:
Expand All @@ -37,16 +39,18 @@ def after_unmarshal(self):
pass

@property
def core_properties(self):
def core_properties(self) -> CoreProperties:
"""|CoreProperties| object providing read/write access to the Dublin Core
properties for this document."""
return self._core_properties_part.core_properties

def iter_rels(self):
def iter_rels(self) -> Iterator[_Relationship]:
"""Generate exactly one reference to each relationship in the package by
performing a depth-first traversal of the rels graph."""

def walk_rels(source, visited=None):
def walk_rels(
source: OpcPackage | Part, visited: list[Part] | None = None
) -> Iterator[_Relationship]:
visited = [] if visited is None else visited
for rel in source.rels.values():
yield rel
Expand Down Expand Up @@ -103,7 +107,7 @@ def main_document_part(self):
"""
return self.part_related_by(RT.OFFICE_DOCUMENT)

def next_partname(self, template):
def next_partname(self, template: str) -> PackURI:
"""Return a |PackURI| instance representing partname matching `template`.
The returned part-name has the next available numeric suffix to distinguish it
Expand Down Expand Up @@ -163,13 +167,13 @@ def save(self, pkg_file: str | IO[bytes]):
PackageWriter.write(pkg_file, self.rels, self.parts)

@property
def _core_properties_part(self):
def _core_properties_part(self) -> CorePropertiesPart:
"""|CorePropertiesPart| object related to this package.
Creates a default core properties part if one is not present (not common).
"""
try:
return self.part_related_by(RT.CORE_PROPERTIES)
return cast(CorePropertiesPart, self.part_related_by(RT.CORE_PROPERTIES))
except KeyError:
core_properties_part = CorePropertiesPart.default(self)
self.relate_to(core_properties_part, RT.CORE_PROPERTIES)
Expand Down
18 changes: 9 additions & 9 deletions src/docx/opc/packuri.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
Also some useful known pack URI strings such as PACKAGE_URI.
"""

from __future__ import annotations

import posixpath
import re

Expand All @@ -16,22 +18,21 @@ class PackURI(str):

_filename_re = re.compile("([a-zA-Z]+)([1-9][0-9]*)?")

def __new__(cls, pack_uri_str):
def __new__(cls, pack_uri_str: str):
if pack_uri_str[0] != "/":
tmpl = "PackURI must begin with slash, got '%s'"
raise ValueError(tmpl % pack_uri_str)
return str.__new__(cls, pack_uri_str)

@staticmethod
def from_rel_ref(baseURI, relative_ref):
"""Return a |PackURI| instance containing the absolute pack URI formed by
translating `relative_ref` onto `baseURI`."""
def from_rel_ref(baseURI: str, relative_ref: str) -> PackURI:
"""The absolute PackURI formed by translating `relative_ref` onto `baseURI`."""
joined_uri = posixpath.join(baseURI, relative_ref)
abs_uri = posixpath.abspath(joined_uri)
return PackURI(abs_uri)

@property
def baseURI(self):
def baseURI(self) -> str:
"""The base URI of this pack URI, the directory portion, roughly speaking.
E.g. ``'/ppt/slides'`` for ``'/ppt/slides/slide1.xml'``. For the package pseudo-
Expand All @@ -40,9 +41,8 @@ def baseURI(self):
return posixpath.split(self)[0]

@property
def ext(self):
"""The extension portion of this pack URI, e.g. ``'xml'`` for
``'/word/document.xml'``.
def ext(self) -> str:
"""The extension portion of this pack URI, e.g. ``'xml'`` for ``'/word/document.xml'``.
Note the period is not included.
"""
Expand Down Expand Up @@ -84,7 +84,7 @@ def membername(self):
"""
return self[1:]

def relative_ref(self, baseURI):
def relative_ref(self, baseURI: str):
"""Return string containing relative reference to package item from `baseURI`.
E.g. PackURI('/ppt/slideLayouts/slideLayout1.xml') would return
Expand Down
Loading

0 comments on commit f246fde

Please sign in to comment.