Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #1045: Added super and subscript support with tests #1046

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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: 2 additions & 0 deletions src/pptx/oxml/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
ST_TextTypeface,
ST_TextWrappingType,
XsdBoolean,
XsdInt,
)
from pptx.oxml.xmlchemy import (
BaseOxmlElement,
Expand Down Expand Up @@ -325,6 +326,7 @@ class CT_TextCharacterProperties(BaseOxmlElement):
u: MSO_TEXT_UNDERLINE_TYPE | None = OptionalAttribute( # pyright: ignore[reportAssignmentType]
"u", MSO_TEXT_UNDERLINE_TYPE
)
baseline: int | None = OptionalAttribute("baseline", XsdInt) # pyright: ignore[reportAssignmentType]

def _new_gradFill(self):
return CT_GradientFillProperties.new_gradFill()
Expand Down
63 changes: 63 additions & 0 deletions src/pptx/text/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,69 @@ def size(self, emu: Length | None):
sz = Emu(emu).centipoints
self._rPr.sz = sz

@property
def superscript(self) -> int | None:
"""
Return the superscript baseline offset if set, otherwise None.

A positive integer represents the text's upward shift relative to the baseline.
The default superscript offset is `30000` (when set via `True`).
"""
if self._rPr.baseline and self._rPr.baseline > 0 :
return self._rPr.baseline
return None

@superscript.setter
def superscript(self, value: bool | int | None):
"""
Set or remove superscript formatting.

- `True` sets the baseline to `30000` (default superscript offset).
- An `int` value explicitly sets the baseline to that amount.
- `False` or `None` removes superscript formatting.
"""
if value is True:
self._rPr.baseline = 30000
elif value is False:
self._rPr.baseline = None
elif isinstance(value, int) and value >= 0:
self._rPr.baseline = value
else:
self._rPr.baseline = None

@property
def subscript(self) -> int | None:
"""
Return the subscript baseline offset if set, otherwise None.

A negative integer represents the text's downward shift relative to the baseline.
The default subscript offset is `-15000` (when set via `True`).
"""
if self._rPr.baseline and self._rPr.baseline < 0:
return self._rPr.baseline

return None

@subscript.setter
def subscript(self, value: bool | int | None):
"""
Set or remove subscript formatting.

- `True` sets the baseline to `-15000` (default subscript offset).
- An `int` value explicitly sets the baseline to that amount.
- `False` or `None` removes subscript formatting.
"""
if value is True:
self._rPr.baseline = -15000
elif value is False:
self._rPr.baseline = None
elif isinstance(value, int) and value <= 0:
self._rPr.baseline = value
else:
self._rPr.baseline = None



@property
def underline(self) -> bool | MSO_TEXT_UNDERLINE_TYPE | None:
"""Indicaties the underline setting for this font.
Expand Down
72 changes: 72 additions & 0 deletions tests/text/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,25 @@ def it_can_change_its_language_id_setting(self, language_id_set_fixture):
font.language_id = new_value
assert font._element.xml == expected_xml

def it_knows_its_superscript_setting(self, superscript_get_fixture):
font, expected_value = superscript_get_fixture
assert font.superscript == expected_value

def it_can_change_its_superscript_setting(self, superscript_set_fixture):
font, new_value, expected_xml = superscript_set_fixture
font.superscript = new_value
assert font._element.xml == expected_xml

def it_knows_its_subscript_setting(self, subscript_get_fixture):
font, expected_value = subscript_get_fixture
assert font.subscript == expected_value

def it_can_change_its_subscript_setting(self, subscript_set_fixture):
font, new_value, expected_xml = subscript_set_fixture
font.subscript = new_value
assert font._element.xml == expected_xml


def it_knows_its_underline_setting(self, underline_get_fixture):
font, expected_value = underline_get_fixture
assert font.underline is expected_value, "got %s" % font.underline
Expand Down Expand Up @@ -636,6 +655,59 @@ def size_set_fixture(self, request):
expected_xml = xml(expected_rPr_cxml)
return font, new_value, expected_xml

@pytest.fixture(
params=[
("a:rPr", None),
("a:rPr{baseline=30000}", 30000),
("a:rPr{baseline=15000}", 15000)
]
)
def superscript_get_fixture(self, request):
rPr_cxml, expected_value = request.param
font = Font(element(rPr_cxml))
return font, expected_value

@pytest.fixture(
params=[
("a:rPr", True, "a:rPr{baseline=30000}"),
("a:rPr", 20000, "a:rPr{baseline=20000}"),
("a:rPr{baseline=30000}", False, "a:rPr"),
("a:rPr{baseline=15000}", None, "a:rPr")
]
)
def superscript_set_fixture(self, request):
rPr_cxml, new_value, expected_rPr_cxml = request.param
font = Font(element(rPr_cxml))
expected_xml = xml(expected_rPr_cxml)
return font, new_value, expected_xml

@pytest.fixture(
params=[
("a:rPr", None),
("a:rPr{baseline=-10000}", -10000),
("a:rPr{baseline=-15000}", -15000)
]
)
def subscript_get_fixture(self, request):
rPr_cxml, expected_value = request.param
font = Font(element(rPr_cxml))
return font, expected_value

@pytest.fixture(
params=[
("a:rPr", True, "a:rPr{baseline=-15000}"),
("a:rPr", -10000, "a:rPr{baseline=-10000}"),
("a:rPr", 10000, "a:rPr"),
("a:rPr{baseline=-10000}", False, "a:rPr"),
("a:rPr{baseline=-15000}", None, "a:rPr")
]
)
def subscript_set_fixture(self, request):
rPr_cxml, new_value, expected_rPr_cxml = request.param
font = Font(element(rPr_cxml))
expected_xml = xml(expected_rPr_cxml)
return font, new_value, expected_xml

@pytest.fixture(
params=[
("a:rPr", None),
Expand Down