From 1e1005ce2ad95d27a14fee9b156abe5291a00d85 Mon Sep 17 00:00:00 2001 From: Steve Canny Date: Sat, 3 Aug 2024 12:18:00 -0700 Subject: [PATCH 1/2] build: modernize build process - Move to `pyproject.toml` - Update support to 3.8+ --- Makefile | 42 ++++++++------- pyproject.toml | 45 ++++++++++++++++ requirements-dev.txt | 5 ++ requirements-docs.txt | 5 ++ requirements-test.txt | 1 + setup.cfg | 0 setup.py | 89 -------------------------------- src/pptx/opc/package.py | 5 +- src/pptx/opc/serialized.py | 3 +- src/pptx/oxml/presentation.py | 2 +- src/pptx/oxml/shapes/graphfrm.py | 2 +- src/pptx/shapes/freeform.py | 3 +- src/pptx/spec.py | 2 +- tox.ini | 37 +------------ 14 files changed, 89 insertions(+), 152 deletions(-) create mode 100644 requirements-dev.txt create mode 100644 requirements-docs.txt delete mode 100644 setup.cfg delete mode 100755 setup.py diff --git a/Makefile b/Makefile index 94891a89b..7a0fddb2e 100644 --- a/Makefile +++ b/Makefile @@ -1,49 +1,55 @@ BEHAVE = behave MAKE = make -PYTHON = python -SETUP = $(PYTHON) ./setup.py -TWINE = $(PYTHON) -m twine - -.PHONY: accept build clean cleandocs coverage docs opendocs +.PHONY: help help: @echo "Please use \`make ' where is one or more of" - @echo " accept run acceptance tests using behave" - @echo " clean delete intermediate work product and start fresh" - @echo " cleandocs delete cached HTML documentation and start fresh" - @echo " coverage run nosetests with coverage" - @echo " docs build HTML documentation using Sphinx (incremental)" - @echo " opendocs open local HTML documentation in browser" - @echo " readme update README.html from README.rst" - @echo " sdist generate a source distribution into dist/" - @echo " upload upload distribution tarball to PyPI" - + @echo " accept run acceptance tests using behave" + @echo " build generate both sdist and wheel suitable for upload to PyPI" + @echo " clean delete intermediate work product and start fresh" + @echo " cleandocs delete cached HTML documentation and start fresh" + @echo " coverage run nosetests with coverage" + @echo " docs build HTML documentation using Sphinx (incremental)" + @echo " opendocs open local HTML documentation in browser" + @echo " test-upload upload distribution to TestPyPI" + @echo " upload upload distribution tarball to PyPI" + +.PHONY: accept accept: $(BEHAVE) --stop +.PHONY: build build: rm -rf dist - $(SETUP) bdist_wheel sdist + python -m build + twine check dist/* +.PHONY: clean clean: find . -type f -name \*.pyc -exec rm {} \; find . -type f -name .DS_Store -exec rm {} \; rm -rf dist .coverage +.PHONY: cleandocs cleandocs: $(MAKE) -C docs clean +.PHONY: coverage coverage: py.test --cov-report term-missing --cov=pptx --cov=tests +.PHONY: docs docs: $(MAKE) -C docs html +.PHONY: opendocs opendocs: open docs/.build/html/index.html +.PHONY: test-upload test-upload: build - $(TWINE) upload --repository testpypi dist/* + twine upload --repository testpypi dist/* +.PHONY: upload upload: clean build - $(TWINE) upload dist/* + twine upload dist/* diff --git a/pyproject.toml b/pyproject.toml index 9868f5fc3..400cb6bfd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,45 @@ +[build-system] +requires = ["setuptools>=61.0.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "python-pptx" +authors = [{name = "Steve Canny", email = "stcanny@gmail.com"}] +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Environment :: Console", + "Intended Audience :: Developers", + "License :: OSI Approved :: MIT License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Topic :: Office/Business :: Office Suites", + "Topic :: Software Development :: Libraries", +] +dependencies = [ + "Pillow>=3.3.2", + "XlsxWriter>=0.5.7", + "lxml>=3.1.0", + "typing_extensions>=4.9.0", +] +description = "Create, read, and update PowerPoint 2007+ (.pptx) files." +dynamic = ["version"] +keywords = ["powerpoint", "ppt", "pptx", "openxml", "office"] +license = { text = "MIT" } +readme = "README.rst" +requires-python = ">=3.8" + +[project.urls] +Changelog = "https://github.com/scanny/python-pptx/blob/master/HISTORY.rst" +Documentation = "https://python-pptx.readthedocs.io/en/latest/" +Homepage = "https://github.com/scanny/python-pptx" +Repository = "https://github.com/scanny/python-pptx" + [tool.black] line-length = 100 @@ -98,3 +140,6 @@ ignore = [ [tool.ruff.lint.isort] known-first-party = ["pptx"] + +[tool.setuptools.dynamic] +version = {attr = "pptx.__version__"} diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 000000000..70096eab2 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,5 @@ +-r requirements-test.txt +build +ruff +setuptools>=61.0.0 +twine diff --git a/requirements-docs.txt b/requirements-docs.txt new file mode 100644 index 000000000..90edd8e31 --- /dev/null +++ b/requirements-docs.txt @@ -0,0 +1,5 @@ +Sphinx==1.8.6 +Jinja2==2.11.3 +MarkupSafe==0.23 +alabaster<0.7.14 +-e . diff --git a/requirements-test.txt b/requirements-test.txt index b542c1af7..9ddd60fd7 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -5,3 +5,4 @@ pytest>=2.5 pytest-coverage pytest-xdist ruff +tox diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index e69de29bb..000000000 diff --git a/setup.py b/setup.py deleted file mode 100755 index 6d9a0d1a5..000000000 --- a/setup.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python - -import os -import re - -from setuptools import find_packages, setup - - -def ascii_bytes_from(path, *paths): - """ - Return the ASCII characters in the file specified by *path* and *paths*. - The file path is determined by concatenating *path* and any members of - *paths* with a directory separator in between. - """ - file_path = os.path.join(path, *paths) - with open(file_path) as f: - ascii_bytes = f.read() - return ascii_bytes - - -# read required text from files -thisdir = os.path.dirname(__file__) -init_py = ascii_bytes_from(thisdir, "src", "pptx", "__init__.py") -readme = ascii_bytes_from(thisdir, "README.rst") -history = ascii_bytes_from(thisdir, "HISTORY.rst") - -# Read the version from pptx.__version__ without importing the package -# (and thus attempting to import packages it depends on that may not be -# installed yet) -version = re.search(r'__version__ = "([^"]+)"', init_py).group(1) - - -NAME = "python-pptx" -VERSION = version -DESCRIPTION = "Generate and manipulate Open XML PowerPoint (.pptx) files" -KEYWORDS = "powerpoint ppt pptx office open xml" -AUTHOR = "Steve Canny" -AUTHOR_EMAIL = "python-pptx@googlegroups.com" -URL = "https://github.com/scanny/python-pptx" -LICENSE = "MIT" -PACKAGES = find_packages(where="src") -PACKAGE_DATA = {"pptx": ["templates/*"]} - -INSTALL_REQUIRES = ["lxml>=3.1.0", "Pillow>=3.3.2", "XlsxWriter>=0.5.7"] - -TEST_SUITE = "tests" -TESTS_REQUIRE = ["behave", "mock", "pyparsing>=2.0.1", "pytest"] - -CLASSIFIERS = [ - "Development Status :: 4 - Beta", - "Environment :: Console", - "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2", - "Programming Language :: Python :: 2.7", - "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.6", - "Topic :: Office/Business :: Office Suites", - "Topic :: Software Development :: Libraries", -] - -LONG_DESCRIPTION = readme + "\n\n" + history - -ZIP_SAFE = False - -params = { - "name": NAME, - "version": VERSION, - "description": DESCRIPTION, - "keywords": KEYWORDS, - "long_description": LONG_DESCRIPTION, - "long_description_content_type": "text/x-rst", - "author": AUTHOR, - "author_email": AUTHOR_EMAIL, - "url": URL, - "license": LICENSE, - "packages": PACKAGES, - "package_data": PACKAGE_DATA, - "package_dir": {"": "src"}, - "install_requires": INSTALL_REQUIRES, - "tests_require": TESTS_REQUIRE, - "test_suite": TEST_SUITE, - "classifiers": CLASSIFIERS, - "zip_safe": ZIP_SAFE, -} - -setup(**params) diff --git a/src/pptx/opc/package.py b/src/pptx/opc/package.py index 03ee5f43b..713759c54 100644 --- a/src/pptx/opc/package.py +++ b/src/pptx/opc/package.py @@ -7,8 +7,7 @@ from __future__ import annotations import collections -from collections.abc import Mapping -from typing import IO, TYPE_CHECKING, DefaultDict, Iterator, Set, cast +from typing import IO, TYPE_CHECKING, DefaultDict, Iterator, Mapping, Set, cast from pptx.opc.constants import RELATIONSHIP_TARGET_MODE as RTM from pptx.opc.constants import RELATIONSHIP_TYPE as RT @@ -428,7 +427,7 @@ def part(self): def _rel_ref_count(self, rId: str) -> int: """Return int count of references in this part's XML to `rId`.""" - return len([r for r in cast(list[str], self._element.xpath("//@r:id")) if r == rId]) + return len([r for r in cast("list[str]", self._element.xpath("//@r:id")) if r == rId]) class PartFactory: diff --git a/src/pptx/opc/serialized.py b/src/pptx/opc/serialized.py index 0942e33cb..92366708b 100644 --- a/src/pptx/opc/serialized.py +++ b/src/pptx/opc/serialized.py @@ -5,8 +5,7 @@ import os import posixpath import zipfile -from collections.abc import Container -from typing import IO, TYPE_CHECKING, Any, Sequence +from typing import IO, TYPE_CHECKING, Any, Container, Sequence from pptx.exc import PackageNotFoundError from pptx.opc.constants import CONTENT_TYPE as CT diff --git a/src/pptx/oxml/presentation.py b/src/pptx/oxml/presentation.py index 254472493..17997c2b1 100644 --- a/src/pptx/oxml/presentation.py +++ b/src/pptx/oxml/presentation.py @@ -76,7 +76,7 @@ def _next_id(self) -> int: MIN_SLIDE_ID = 256 MAX_SLIDE_ID = 2147483647 - used_ids = [int(s) for s in cast(list[str], self.xpath("./p:sldId/@id"))] + used_ids = [int(s) for s in cast("list[str]", self.xpath("./p:sldId/@id"))] simple_next = max([MIN_SLIDE_ID - 1] + used_ids) + 1 if simple_next <= MAX_SLIDE_ID: return simple_next diff --git a/src/pptx/oxml/shapes/graphfrm.py b/src/pptx/oxml/shapes/graphfrm.py index cf32377c2..efa0b3632 100644 --- a/src/pptx/oxml/shapes/graphfrm.py +++ b/src/pptx/oxml/shapes/graphfrm.py @@ -112,7 +112,7 @@ def _oleObj(self) -> CT_OleObject | None: choices. The last one should suit best for reading purposes because it contains the lowest common denominator. """ - oleObjs = cast(list[CT_OleObject], self.xpath(".//p:oleObj")) + oleObjs = cast("list[CT_OleObject]", self.xpath(".//p:oleObj")) return oleObjs[-1] if oleObjs else None diff --git a/src/pptx/shapes/freeform.py b/src/pptx/shapes/freeform.py index e05b3484f..afe87385e 100644 --- a/src/pptx/shapes/freeform.py +++ b/src/pptx/shapes/freeform.py @@ -2,8 +2,7 @@ from __future__ import annotations -from collections.abc import Sequence -from typing import TYPE_CHECKING, Iterable, Iterator +from typing import TYPE_CHECKING, Iterable, Iterator, Sequence from pptx.util import Emu, lazyproperty diff --git a/src/pptx/spec.py b/src/pptx/spec.py index 1e7bffb36..e9d3b7d58 100644 --- a/src/pptx/spec.py +++ b/src/pptx/spec.py @@ -16,7 +16,7 @@ if TYPE_CHECKING: from typing_extensions import TypeAlias -AdjustmentValue: TypeAlias = tuple[str, int] +AdjustmentValue: TypeAlias = "tuple[str, int]" class ShapeSpec(TypedDict): diff --git a/tox.ini b/tox.ini index 223cc0ffe..37acaa5fa 100644 --- a/tox.ini +++ b/tox.ini @@ -1,42 +1,9 @@ -# -# Configuration for tox and pytest - -[flake8] -exclude = dist,docs,*.egg-info,.git,lab,ref,_scratch,spec,.tox -ignore = - # -- E203 - whitespace before ':'. Black disagrees for slice expressions. - E203, - - # -- W503 - line break before binary operator. Black has a different opinion about - # -- this, that binary operators should appear at the beginning of new-line - # -- expression segments. I agree because right is ragged and left lines up. - W503 -max-line-length = 88 - [tox] -envlist = py27, py38, py311 -requires = virtualenv<20.22.0 -skip_missing_interpreters = false +envlist = py38, py39, py310, py311, py312 [testenv] -deps = - behave==1.2.5 - lxml>=3.1.0 - Pillow>=3.3.2 - pyparsing>=2.0.1 - pytest - XlsxWriter>=0.5.7 +deps = -rrequirements-test.txt commands = py.test -qx behave --format progress --stop --tags=-wip - -[testenv:py27] -deps = - behave==1.2.5 - lxml>=3.1.0 - mock - Pillow>=3.3.2 - pyparsing>=2.0.1 - pytest - XlsxWriter>=0.5.7 From 0f42d308094e1eaa5e38ea0e61e5774bbd94e985 Mon Sep 17 00:00:00 2001 From: Steve Canny Date: Sat, 3 Aug 2024 12:24:14 -0700 Subject: [PATCH 2/2] release: prepare v1.0.0 release --- HISTORY.rst | 5 +++-- src/pptx/__init__.py | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index 73c3bacef..6f0835045 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,13 +3,14 @@ Release History --------------- -0.6.24-dev4 -+++++++++++++++++++ +1.0.0 (2024-08-03) +++++++++++++++++++ - fix: #929 raises on JPEG with image/jpg MIME-type - fix: #943 remove mention of a Px Length subtype - fix: #972 next-slide-id fails in rare cases - fix: #990 do not require strict timestamps for Zip +- Add type annotations 0.6.23 (2023-11-02) diff --git a/src/pptx/__init__.py b/src/pptx/__init__.py index 27d6306a1..3baec7376 100644 --- a/src/pptx/__init__.py +++ b/src/pptx/__init__.py @@ -25,7 +25,7 @@ if TYPE_CHECKING: from pptx.opc.package import Part -__version__ = "0.6.24-dev4" +__version__ = "1.0.0" sys.modules["pptx.exceptions"] = exceptions del sys