Skip to content
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
Binary file modified docs/_static/img/add-picture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/add-shape.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/add-textbox.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/bullet-slide.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/chart-04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/chart-06.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/chart-08.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/freeform-03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/hello-world.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/table-01.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/table-02.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/table-03.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/table-04.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/_static/img/table-07.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified features/steps/test_files/just-two-mice.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified features/steps/test_files/monty-truth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified features/steps/test_files/python-powered.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified features/steps/test_files/sonic.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/pptx/enum/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ def __str__(self):
"""The symbolic name and string value of this member, e.g. 'MIDDLE (3)'."""
return f"{self.name} ({self.value})"

@classmethod
def from_value(cls, value: int):
"""Return the enum member corresponding to the given integer value."""
for member in cls:
if member.value == value:
return member
raise ValueError(f"No enum member with value {value}")


class BaseXmlEnum(int, enum.Enum):
"""Base class for Enums that also map XML attr values.
Expand Down
4 changes: 4 additions & 0 deletions src/pptx/oxml/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -457,6 +457,8 @@ def register_element_cls(nsptagname: str, cls: Type[BaseOxmlElement]):
CT_TextSpacing,
CT_TextSpacingPercent,
CT_TextSpacingPoint,
CT_TextCharBullet,
CT_TextNoBullet,
)

register_element_cls("a:bodyPr", CT_TextBodyProperties)
Expand All @@ -476,6 +478,8 @@ def register_element_cls(nsptagname: str, cls: Type[BaseOxmlElement]):
register_element_cls("a:spcBef", CT_TextSpacing)
register_element_cls("a:spcPct", CT_TextSpacingPercent)
register_element_cls("a:spcPts", CT_TextSpacingPoint)
register_element_cls("a:buNone", CT_TextNoBullet)
register_element_cls("a:buChar", CT_TextCharBullet)
register_element_cls("a:txBody", CT_TextBody)
register_element_cls("c:txPr", CT_TextBody)
register_element_cls("p:txBody", CT_TextBody)
Expand Down
52 changes: 51 additions & 1 deletion 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,
XsdString,
)
from pptx.oxml.xmlchemy import (
BaseOxmlElement,
Expand Down Expand Up @@ -245,7 +246,9 @@ def autofit(self):
return None

@autofit.setter
def autofit(self, value: MSO_AUTO_SIZE | None):
def autofit(self, value: MSO_AUTO_SIZE | None | int):
if isinstance(value, int):
value = MSO_AUTO_SIZE.from_value(value)
if value is not None and value not in MSO_AUTO_SIZE:
raise ValueError(
f"only None or a member of the MSO_AUTO_SIZE enumeration can be assigned to"
Expand Down Expand Up @@ -498,6 +501,12 @@ class CT_TextParagraphProperties(BaseOxmlElement):
spcAft: CT_TextSpacing | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
"a:spcAft", successors=_tag_seq[3:]
)
buNone: CT_TextNoBullet | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
"a:buNone", successors=_tag_seq[11:]
)
buChar: CT_TextCharBullet | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
"a:buChar", successors=_tag_seq[13:]
)
defRPr: CT_TextCharacterProperties | None = ZeroOrOne( # pyright: ignore[reportAssignmentType]
"a:defRPr", successors=_tag_seq[16:]
)
Expand All @@ -509,6 +518,31 @@ class CT_TextParagraphProperties(BaseOxmlElement):
) # pyright: ignore[reportAssignmentType]
del _tag_seq

@property
def bullet(self):
buNone = self.buNone
buChar = self.buChar
if buNone is not None:
return None
if buChar is not None:
return buChar.char

@bullet.setter
def bullet(self, value):
self._remove_buNone()
self._remove_buChar()
if value is None:
return
if isinstance(value, bool):
if value:
buChar = self._add_buChar()
buChar.char = "\u2022"
else:
self._add_buNone()
else:
buChar = self._add_buChar()
buChar.char = value

@property
def line_spacing(self) -> float | Length | None:
"""The spacing between baselines of successive lines in this paragraph.
Expand Down Expand Up @@ -616,3 +650,19 @@ class CT_TextSpacingPoint(BaseOxmlElement):
val: Length = RequiredAttribute( # pyright: ignore[reportAssignmentType]
"val", ST_TextSpacingPoint
)


class CT_TextNoBullet(BaseOxmlElement):
"""
<a:buNone> element, specifying that a paragraph should not be bulleted.
"""

pass


class CT_TextCharBullet(BaseOxmlElement):
"""
<a:buChar> element, specifying that a paragraph should have a character bullet.
"""

char = RequiredAttribute("char", XsdString)
15 changes: 14 additions & 1 deletion src/pptx/shapes/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from __future__ import annotations

from pptx.dml.line import LineFormat
from pptx.enum.shapes import MSO_SHAPE_TYPE
from pptx.enum.shapes import MSO_CONNECTOR_TYPE, MSO_SHAPE_TYPE
from pptx.shapes.base import BaseShape
from pptx.util import Emu, lazyproperty

Expand Down Expand Up @@ -218,6 +218,19 @@ def end_y(self, value):
cxnSp.y = new_y
cxnSp.cy = dy - cy

@property
def connector_type(self):
# <a:prstGeom prst="{prst}">
if self._element.spPr.prstGeom is None:
raise ValueError("Connector does not have a prstGeom element")
for type in iter(MSO_CONNECTOR_TYPE):
if type is MSO_CONNECTOR_TYPE.MIXED:
continue
type_identifier = MSO_CONNECTOR_TYPE.to_xml(type)
if 'prst="' + type_identifier in self._element.spPr.prstGeom.xml:
return type
raise ValueError("Connector does not have a effective connector type")

def get_or_add_ln(self):
"""Helper method required by |LineFormat|."""
return self._element.spPr.get_or_add_ln()
Expand Down
55 changes: 53 additions & 2 deletions src/pptx/text/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from typing import TYPE_CHECKING, Iterator, cast

from lxml import etree
from pptx.dml.fill import FillFormat
from pptx.enum.dml import MSO_FILL
from pptx.enum.lang import MSO_LANGUAGE_ID
Expand Down Expand Up @@ -307,7 +307,10 @@ def color(self) -> ColorFormat:
"""The |ColorFormat| instance that provides access to the color settings for this font."""
if self.fill.type != MSO_FILL.SOLID:
self.fill.solid()
return self.fill.fore_color
try:
return str(self.fill.fore_color.rgb)
except:
return None

@lazyproperty
def fill(self) -> FillFormat:
Expand Down Expand Up @@ -421,6 +424,27 @@ def underline(self, value: bool | MSO_TEXT_UNDERLINE_TYPE | None):
value = MSO_UNDERLINE.NONE
self._element.u = value

def get_attrs(self):
return (
self.bold,
self.color,
self.italic,
self.name,
self.size.pt if self.size is not None else None,
self.underline,
)

def __hash__(self):
return hash(self.get_attrs())

def __eq__(self, other):
if not isinstance(other, Font):
return False
return self.get_attrs() == other.get_attrs()

def __repr__(self):
return f"Font: name={self.name}, size={self.size}"


class _Hyperlink(Subshape):
"""Text run hyperlink object.
Expand Down Expand Up @@ -631,6 +655,33 @@ def _pPr(self) -> CT_TextParagraphProperties:
"""
return self._p.get_or_add_pPr()

@property
def bullet(self):
pPr = self._p.pPr
if pPr is None:
return None
return pPr.bullet

@bullet.setter
def bullet(self, value):
pPr = self._p.get_or_add_pPr()
if (
pPr.find(
"a:buFont",
namespaces={"a": "http://schemas.openxmlformats.org/drawingml/2006/main"},
)
is None
):
buFont = etree.Element(
"{http://schemas.openxmlformats.org/drawingml/2006/main}buFont",
typeface="Wingdings",
pitchFamily="0",
charset="2",
panose="05000000000000000000",
)
pPr.insert(0, buFont)
pPr.bullet = value


class _Run(Subshape):
"""Text run object. Corresponds to `a:r` child element in a paragraph."""
Expand Down
2 changes: 1 addition & 1 deletion src/pptx/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def mm(self) -> float:
@property
def pt(self) -> float:
"""Floating point length in points."""
return self / float(self._EMUS_PER_PT)
return self // self._EMUS_PER_PT


class Inches(Length):
Expand Down
Binary file modified tests/test_files/expanded_pptx/docProps/thumbnail.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/test_files/monty-truth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/test_files/python-powered.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.