diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 9c01fc4..01d007b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -34,24 +34,16 @@ jobs: strategy: # https://blog.jaraco.com/efficient-use-of-ci-resources/ matrix: + # This library is Windows-only + # pywin32 does not yet support pypy: mhammond/pywin32#1289 & pypy/pypy#3836 + # pywin32's Python 3.13 support is not released yet: mhammond/pywin32#2367 python: - - "3.9" - - "3.13" + - "3.9" + - "3.10" + - "3.11" + - "3.12" platform: - - ubuntu-latest - - macos-latest - - windows-latest - include: - - python: "3.10" - platform: ubuntu-latest - - python: "3.11" - platform: ubuntu-latest - - python: "3.12" - platform: ubuntu-latest - - python: "3.14" - platform: ubuntu-latest - - python: pypy3.10 - platform: ubuntu-latest + - windows-latest runs-on: ${{ matrix.platform }} continue-on-error: ${{ matrix.python == '3.14' }} steps: @@ -73,7 +65,7 @@ jobs: job: - diffcov - docs - runs-on: ubuntu-latest + runs-on: windows-latest steps: - uses: actions/checkout@v4 with: diff --git a/build-exe.py b/build-exe.py index 47191ec..ad394f8 100644 --- a/build-exe.py +++ b/build-exe.py @@ -2,21 +2,10 @@ Build script to create a doc-to-pdf convert server as a Windows executable. """ -import os -import textwrap - - -setup_params = dict( - console=['server.py'], - options=dict( - py2exe=dict( - packages=['pkg_resources'], - ), - ), - script_args=('py2exe',), -) - if __name__ == '__main__': + import os + import textwrap + from setuptools import setup __import__('py2exe') @@ -25,5 +14,13 @@ convert.ConvertServer.start_server() """ open('server.py', 'w').write(textwrap.dedent(code)) - setup(**setup_params) + setup( + console=['server.py'], + options=dict( + py2exe=dict( + packages=['pkg_resources'], + ), + ), + script_args=('py2exe',), # type: ignore[arg-type] # python/typeshed#12595 + ) os.remove('server.py') diff --git a/jaraco/__init__.py b/jaraco/__init__.py index 0d1f7ed..69e3be5 100644 --- a/jaraco/__init__.py +++ b/jaraco/__init__.py @@ -1 +1 @@ -__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore +__path__ = __import__('pkgutil').extend_path(__path__, __name__) diff --git a/jaraco/office/convert.py b/jaraco/office/convert.py index 904a08c..4cb0967 100644 --- a/jaraco/office/convert.py +++ b/jaraco/office/convert.py @@ -1,8 +1,12 @@ -import os import argparse +import os +import threading from contextlib import contextmanager -from jaraco.path import save_to_file, replace_extension +import pythoncom +from win32com.client import Dispatch, constants + +from jaraco.path import replace_extension, save_to_file @contextmanager @@ -23,10 +27,6 @@ class Converter: """ def __init__(self): - from win32com.client import Dispatch - import pythoncom - import threading - if threading.current_thread().getName() != 'MainThread': pythoncom.CoInitialize() self.word = Dispatch('Word.Application') @@ -36,8 +36,6 @@ def convert(self, docfile_string, target_format=None): Take a string (in memory) and return it as a string of the target format (also as a string in memory). """ - from win32com.client import constants - target_format = target_format or getattr(constants, 'wdFormatPDF', 17) with save_to_file(docfile_string) as docfile: @@ -80,17 +78,18 @@ class ConvertServer: def index(self): return form - index.exposed = True # type: ignore + index.exposed = True # type: ignore[attr-defined] def convert(self, document): + import cherrypy + cherrypy.response.headers['Content-Type'] = 'application/pdf' return Converter().convert(document.file.read()) - convert.exposed = True # type: ignore + convert.exposed = True # type: ignore[attr-defined] @staticmethod def start_server(): - global cherrypy import cherrypy parser = argparse.ArgumentParser() diff --git a/jaraco/office/excel.py b/jaraco/office/excel.py index 84528af..ca4224f 100644 --- a/jaraco/office/excel.py +++ b/jaraco/office/excel.py @@ -1,5 +1,7 @@ import contextlib +from win32com.client import Dispatch + from jaraco.path import tempfile_context @@ -22,8 +24,6 @@ def to_dict(values): def open_workbook(filename): - from win32com.client import Dispatch - app = Dispatch('Excel.Application') return app.Workbooks.Open(filename) diff --git a/jaraco/office/grep.py b/jaraco/office/grep.py index 5ac427e..d701842 100644 --- a/jaraco/office/grep.py +++ b/jaraco/office/grep.py @@ -1,10 +1,11 @@ -import re +from __future__ import annotations -from win32com.client import Dispatch +import re +from win32com.client import Dispatch, dynamic try: - app = Dispatch('Excel.Application') + app: dynamic.CDispatch | None = Dispatch('Excel.Application') except Exception: app = None diff --git a/mypy.ini b/mypy.ini index efcb8cb..c79da1a 100644 --- a/mypy.ini +++ b/mypy.ini @@ -13,3 +13,11 @@ explicit_package_bases = True disable_error_code = # Disable due to many false positives overload-overlap, + +# jaraco/jaraco.path#2 +[mypy-jaraco.path.*] +ignore_missing_imports = True + +# cherrypy/cherrypy#1510 +[mypy-cherrypy.*] +ignore_missing_imports = True diff --git a/pyproject.toml b/pyproject.toml index f5fcadd..65beba3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,6 +20,7 @@ classifiers = [ requires-python = ">=3.9" dependencies = [ "jaraco.path", + 'pywin32; platform_system == "Windows"', ] dynamic = ["version"] keywords = ["excel office word"] @@ -33,7 +34,7 @@ test = [ "pytest >= 6, != 8.1.*", # local - 'pypiwin32; platform_system == "Windows"', + "cherrypy", # Optional dependency for ConvertServer ] doc = [ @@ -65,6 +66,8 @@ type = [ "pytest-mypy", # local + "types-pywin32", + "types-setuptools", ] @@ -74,7 +77,3 @@ doc-to-pdf-server = "jaraco.office.convert:ConvertServer.start_server" [tool.setuptools_scm] - - -[tool.pytest-enabler.mypy] -# Disabled due to jaraco/skeleton#143