diff --git a/.gitignore b/.gitignore index d139662bf..ceec10bc8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,8 +15,7 @@ docs/build/ sourcebuild/ !sourcebuild/patches -src/pypdfium2/raw.py -src/pypdfium2/pdfium +src/pypdfium2_raw/bindings.py *.so *.dll diff --git a/.reuse/dep5 b/.reuse/dep5 index 3fc12a80a..965d72f36 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -11,7 +11,7 @@ Source: https://github.com/pypdfium2-team/pypdfium2 Files: req/*.txt - bindings/raw.py + bindings/bindings.py autorelease/* RELEASE.md tests/expectations/* diff --git a/README.md b/README.md index efcd9343a..13519cfbf 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,7 @@ Nonetheless, the following guide may be helpful to get started with the raw API, Python `bytes` are converted to `FPDF_STRING` by ctypes autoconversion. When passing a string to a C function, it must always be null-terminated, as the function merely receives a pointer to the first item and then continues to read memory until it finds a null terminator. -[^bindings_decl]: From the auto-generated bindings file, which is not part of the repository. It is built into wheels, or created on installation. If you have an editable install, the bindings file may be found at `src/raw.py`. +[^bindings_decl]: From the auto-generated bindings file. We maintain a reference copy at `bindings/bindings.py`. Or if you have an editable install, there will also be `src/pypdfium2_raw/bindings.py`. * While some functions are quite easy to use, things soon get more complex. First of all, function parameters are not only used for input, but also for output: diff --git a/bindings/README.md b/bindings/README.md index 3676be8de..433d29036 100644 --- a/bindings/README.md +++ b/bindings/README.md @@ -5,7 +5,7 @@ [#192]: https://github.com/pypdfium2-team/pypdfium2/issues/192 -This directory contains a reference bindings file for pypdfium2 ([raw.py](./raw.py)). +This directory contains a reference bindings file for pypdfium2 ([bindings.py](./bindings.py)). It is updated automatically on release. This helps track changes to the bindings. See [#192] for an extended rationale. diff --git a/bindings/raw.py b/bindings/bindings.py similarity index 100% rename from bindings/raw.py rename to bindings/bindings.py diff --git a/pyproject.toml b/pyproject.toml index 3744bb24d..27f000b0a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -16,8 +16,7 @@ requires = [ name = "pypdfium2" description = "Python bindings to PDFium" readme = "README.md" -requires-python = ">= 3.6" -dynamic = ["version"] +dynamic = ["version", "requires-python"] keywords = ["pdf", "pdfium"] authors = [ {name = "pypdfium2-team"}, @@ -58,6 +57,3 @@ license-files = [ "LICENSES/LicenseRef-PdfiumThirdParty.txt", ".reuse/dep5", ] - -[tool.setuptools.packages.find] -where = ["src"] diff --git a/run b/run index e5ab250d7..c82c9ca13 100755 --- a/run +++ b/run @@ -14,7 +14,7 @@ function check() { } function clean() { - rm -rf src/pypdfium2.egg-info/ dist data/* + rm -rf src/pypdfium2.egg-info/ dist/ data/* rm -f tests/output/* tests_old/output/* src/pypdfium2.egg-info/SOURCES.txt } @@ -39,7 +39,7 @@ test) python3 -m pytest tests/ tests_old/ $args;; coverage) - python3 -m coverage run --omit "tests/*,tests_old/*,src/pypdfium2/raw.py,setupsrc/*" -m pytest tests/ tests_old/ $args + python3 -m coverage run --omit "tests/*,tests_old/*,src/pypdfium2_raw/bindings.py,setupsrc/*" -m pytest tests/ tests_old/ $args python3 -m coverage report;; docs-build) diff --git a/setup.py b/setup.py index adfd263a2..6474a5de1 100644 --- a/setup.py +++ b/setup.py @@ -12,24 +12,30 @@ sys.path.insert(0, str(Path(__file__).parent / "setupsrc")) from pypdfium2_setup.emplace import get_pdfium from pypdfium2_setup.packaging_base import ( + # TODO consider glob import or dotted access? purge_pdfium_versions, BinarySpec_EnvVar, PlatformTarget_None, + ModulesSpec_EnvVar, ) def main(): - from pypdfium2_setup.setup_base import mkwheel, SetupKws + from pypdfium2_setup.setup_base import mkwheel, get_setup_kws + + binary_spec = os.environ.get(BinarySpec_EnvVar, "") + modules_spec = os.environ.get(ModulesSpec_EnvVar, "") + if modules_spec: + modules_spec = modules_spec.split(",") - binary_spec = os.environ.get(BinarySpec_EnvVar, "").strip() if binary_spec == PlatformTarget_None: purge_pdfium_versions() - setuptools.setup(**SetupKws) + setuptools.setup(**get_setup_kws(modules_spec)) return pl_name = get_pdfium(binary_spec) - mkwheel(pl_name) + mkwheel(pl_name, modules_spec) if __name__ == "__main__": diff --git a/setupsrc/pypdfium2_setup/craft_packages.py b/setupsrc/pypdfium2_setup/craft_packages.py index 4f3e206c0..7005fa7dc 100644 --- a/setupsrc/pypdfium2_setup/craft_packages.py +++ b/setupsrc/pypdfium2_setup/craft_packages.py @@ -23,7 +23,7 @@ def __init__(self): # FIXME some degree of duplication with base::get_platfiles() file_names = [BindingsFileName, LibnameForSystem[Host.system]] - self.files = [fp for fp in [ModuleDir / fn for fn in file_names] if fp.exists()] + self.files = [fp for fp in [RawModuleDir / fn for fn in file_names] if fp.exists()] if len(self.files) == 0: return elif len(self.files) != 2: @@ -38,7 +38,7 @@ def pop(self): if self.tmpdir is None: return for fp in self.files: - shutil.move(self.tmpdir_path / fp.name, ModuleDir) + shutil.move(self.tmpdir_path / fp.name, RawModuleDir) self.tmpdir.cleanup() diff --git a/setupsrc/pypdfium2_setup/emplace.py b/setupsrc/pypdfium2_setup/emplace.py index 1bc4f04a9..412d923d8 100644 --- a/setupsrc/pypdfium2_setup/emplace.py +++ b/setupsrc/pypdfium2_setup/emplace.py @@ -74,7 +74,6 @@ def main(): ) parser.add_argument( "binary_spec", - type = str.strip, default = os.environ.get(BinarySpec_EnvVar, ""), nargs = "?", help = f"The binary specifier. Same format as of ${BinarySpec_EnvVar} on setup.", diff --git a/setupsrc/pypdfium2_setup/packaging_base.py b/setupsrc/pypdfium2_setup/packaging_base.py index 4c1aa7d59..6cf39b024 100644 --- a/setupsrc/pypdfium2_setup/packaging_base.py +++ b/setupsrc/pypdfium2_setup/packaging_base.py @@ -18,14 +18,15 @@ VerStatusFileName = ".pdfium_version.txt" V8StatusFileName = ".pdfium_is_v8.txt" # NOTE if renaming BindingsFileName, also rename `bindings/$FILE` -BindingsFileName = "raw.py" +BindingsFileName = "bindings.py" HomeDir = Path.home() SourceTree = Path(__file__).parents[2] DataTree = SourceTree / "data" SB_Dir = SourceTree / "sourcebuild" -ModuleDir = SourceTree / "src" / "pypdfium2" -VersionFile = ModuleDir / "version.py" +RawModuleDir = SourceTree / "src" / "pypdfium2_raw" +HelpersModuleDir = SourceTree / "src" / "pypdfium2" +VersionFile = HelpersModuleDir / "version.py" Changelog = SourceTree / "docs" / "devel" / "changelog.md" ChangelogStaging = SourceTree / "docs" / "devel" / "changelog_staging.md" AutoreleaseDir = SourceTree / "autorelease" @@ -40,6 +41,11 @@ PlatformTarget_Auto = "auto" # host VersionTarget_Latest = "latest" +ModulesSpec_EnvVar = "PYPDFIUM_MODULES" +ModuleRaw = "raw" +ModuleHelpers = "helpers" +ModulesAll = [ModuleRaw, ModuleHelpers] + RepositoryURL = "https://github.com/pypdfium2-team/pypdfium2" PDFium_URL = "https://pdfium.googlesource.com/pdfium" DepotTools_URL = "https://chromium.googlesource.com/chromium/tools/depot_tools.git" @@ -325,9 +331,9 @@ def clean_platfiles(): deletables = [ SourceTree / "build", - ModuleDir / BindingsFileName, + RawModuleDir / BindingsFileName, ] - deletables += [ModuleDir / fn for fn in MainLibnames] + deletables += [RawModuleDir / fn for fn in MainLibnames] for fp in deletables: if fp.is_file(): @@ -367,7 +373,7 @@ def emplace_platfiles(pl_name): for fp in platfiles: if not fp.exists(): raise RuntimeError(f"Platform file missing: {fp}") - shutil.copy(fp, ModuleDir) + shutil.copy(fp, RawModuleDir) def get_changelog_staging(flush=False): diff --git a/setupsrc/pypdfium2_setup/setup_base.py b/setupsrc/pypdfium2_setup/setup_base.py index b030e25cb..a714c6d5e 100644 --- a/setupsrc/pypdfium2_setup/setup_base.py +++ b/setupsrc/pypdfium2_setup/setup_base.py @@ -8,13 +8,7 @@ sys.path.insert(0, str(Path(__file__).parents[1])) # TODO consider glob import or dotted access -from pypdfium2_setup.packaging_base import ( - VerNamespace, - LibnameForSystem, - plat_to_system, - get_wheel_tag, - emplace_platfiles, -) +from pypdfium2_setup.packaging_base import * def bdist_factory(pl_name): @@ -36,12 +30,28 @@ def has_ext_modules(self): return True -SetupKws = dict( - version = VerNamespace["V_PYPDFIUM2"], -) +def get_setup_kws(modnames=None): + + if not modnames: + modnames = ModulesAll + + module_dirs = {} + if ModuleRaw in modnames: + module_dirs["pypdfium2_raw"] = "src/pypdfium2_raw" + if ModuleHelpers in modnames: + module_dirs["pypdfium2"] = "src/pypdfium2" + assert len(module_dirs) in (1, 2) + assert len(modnames) == len(module_dirs) + + return dict( + version = VerNamespace["V_PYPDFIUM2"], + package_dir = module_dirs, + # NOTE if necessary, python req could be set dynamically depending on included modules + python_requires = ">= 3.6", + ) -def mkwheel(pl_name): +def mkwheel(pl_name, modnames=None): emplace_platfiles(pl_name) system = plat_to_system(pl_name) @@ -51,5 +61,5 @@ def mkwheel(pl_name): package_data = {"": [libname]}, cmdclass = {"bdist_wheel": bdist_factory(pl_name)}, distclass = BinaryDistribution, - **SetupKws, + **get_setup_kws(modnames), ) diff --git a/src/pypdfium2/raw.py b/src/pypdfium2/raw.py new file mode 100644 index 000000000..3c667a42e --- /dev/null +++ b/src/pypdfium2/raw.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2023 geisserml +# SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause + +from pypdfium2_raw.bindings import * diff --git a/src/pypdfium2_raw/__init__.py b/src/pypdfium2_raw/__init__.py new file mode 100644 index 000000000..3c667a42e --- /dev/null +++ b/src/pypdfium2_raw/__init__.py @@ -0,0 +1,4 @@ +# SPDX-FileCopyrightText: 2023 geisserml +# SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause + +from pypdfium2_raw.bindings import * diff --git a/tests_old/test_setup.py b/tests_old/test_setup.py index f5d7cf1c9..d1810de94 100644 --- a/tests_old/test_setup.py +++ b/tests_old/test_setup.py @@ -102,8 +102,8 @@ def test_paths(): assert pkg_base.SourceTree == SourceTree assert pkg_base.DataTree == SourceTree / "data" assert pkg_base.SB_Dir == SourceTree / "sourcebuild" - assert pkg_base.ModuleDir == SourceTree / "src" / "pypdfium2" - assert pkg_base.VersionFile == Path(pkg_base.ModuleDir) / "version.py" + assert pkg_base.HelpersModuleDir == SourceTree / "src" / "pypdfium2" + assert pkg_base.VersionFile == Path(pkg_base.HelpersModuleDir) / "version.py" # update_pdfium