From 57a129591178ea0470824d95879165d9a0ac7b8c Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 22 Oct 2022 21:04:26 -0400 Subject: [PATCH 1/3] Add support for editable installs Signed-off-by: Jean-Christophe Morin --- .gitignore | 2 ++ MANIFEST.in | 2 ++ docs/tutorials/quickstart.md | 2 +- setup.py | 39 +++++++++++++++--------------------- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/.gitignore b/.gitignore index afb5e9de65..dd2e1c7e4a 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,5 @@ docs/_build .tox cpp_cov_html/ lcov_html_report/ +*.so +*.pyd diff --git a/MANIFEST.in b/MANIFEST.in index 64d9daf540..567cb83e05 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -23,6 +23,8 @@ exclude */.DS_Store exclude .clang-format exclude OTIO_VERSION.json global-exclude *.pyc +global-exclude *.so +global-exclude *.pyd prune maintainers prune tsc diff --git a/docs/tutorials/quickstart.md b/docs/tutorials/quickstart.md index 34a80fe3cd..283513b592 100644 --- a/docs/tutorials/quickstart.md +++ b/docs/tutorials/quickstart.md @@ -62,7 +62,7 @@ with OpenTimelineIO due to spaces in the path. ## To build OTIO for Python development: -+ `python -m pip install .` ++ `python -m pip install -e .` ## To build OTIO for both C++ and Python development: diff --git a/setup.py b/setup.py index 6986f3ec19..d561a34a3e 100644 --- a/setup.py +++ b/setup.py @@ -46,23 +46,25 @@ def join_args(args): return ' '.join(map(shlex.quote, args)) -class CMakeExtension(Extension): - def __init__(self, name): - Extension.__init__(self, name, sources=[]) - - class OTIO_build_ext(setuptools.command.build_ext.build_ext): """ def initialize_options(self): super(setuptools.command.build_ext.build_ext, self).initialize_options() """ + built = False + def run(self): + self.announce('running OTIO build_ext', level=2) + super().run() + + def build_extension(self, _ext: Extension): # This works around the fact that we build _opentime and _otio # extensions as a one-shot cmake invocation. Usually we'd build each # separately using build_extension. - self.announce('running OTIO build_ext', level=2) - self.build() + if not self.built: + self.build() + self.built = True def build(self): self.build_temp_dir = ( @@ -256,22 +258,15 @@ class OTIO_build_py(setuptools.command.build_py.build_py): """Stamps PROJECT_METADATA into __init__ files.""" def run(self): - setuptools.command.build_py.build_py.run(self) + super().run() - if not self.dry_run: + if not self.dry_run and not self.editable_mode: + # Only run when not in dry-mode (a dry run should not have any side effect) + # and in non-editable mode. We don't want to edit files when in editable + # mode because that could lead to modifications to the source files. _append_version_info_to_init_scripts(self.build_lib) -def test_otio(): - """Discovers and runs tests""" - try: - # Clear the environment of a preset media linker - del os.environ['OTIO_DEFAULT_MEDIA_LINKER'] - except KeyError: - pass - return unittest.TestLoader().discover('tests') - - # copied from first paragraph of README.md LONG_DESCRIPTION = """OpenTimelineIO is an interchange format and API for editorial cut information. OTIO is not a container format for media, rather it @@ -339,8 +334,8 @@ def test_otio(): ), ext_modules=[ - CMakeExtension('_opentimelineio'), - CMakeExtension('_opentime'), + Extension('opentimelineio._otio', sources=[]), + Extension('opentimelineio._opentime', sources=[]), ], package_dir={ @@ -382,8 +377,6 @@ def test_otio(): ] }, - test_suite='setup.test_otio', - # because we need to open() the adapters manifest, we aren't zip-safe zip_safe=False, From 2a2a27ad0e8df9e5e8e89d3dcf9dee8da7c29c8d Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sat, 22 Oct 2022 21:12:31 -0400 Subject: [PATCH 2/3] Remove unused import Signed-off-by: Jean-Christophe Morin --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index d561a34a3e..a1d41b06f6 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,6 @@ import sys import platform import subprocess -import unittest import tempfile import shutil From ad62152a9c0b6f3c9c5efafd7d134b88fe72d202 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Morin Date: Sun, 23 Oct 2022 15:03:33 -0400 Subject: [PATCH 3/3] Add comments Signed-off-by: Jean-Christophe Morin --- setup.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index a1d41b06f6..8624b86878 100644 --- a/setup.py +++ b/setup.py @@ -55,12 +55,17 @@ def initialize_options(self): def run(self): self.announce('running OTIO build_ext', level=2) + # Let the original build_ext class do its job. + # This is rather important because build_ext.run takes care of a + # couple of things, one of which is to copy the built files into + # the source tree (in src/py-opentimelineio/opentimelineio) + # when building in editable mode. super().run() def build_extension(self, _ext: Extension): # This works around the fact that we build _opentime and _otio - # extensions as a one-shot cmake invocation. Usually we'd build each - # separately using build_extension. + # extensions as a one-shot cmake invocation. Setuptools calls + # build_extension for each Extension registered in the setup function. if not self.built: self.build() self.built = True @@ -263,6 +268,8 @@ def run(self): # Only run when not in dry-mode (a dry run should not have any side effect) # and in non-editable mode. We don't want to edit files when in editable # mode because that could lead to modifications to the source files. + # Note that setuptools will set self.editable_mode to True + # when "pip install -e ." is run. _append_version_info_to_init_scripts(self.build_lib) @@ -333,6 +340,11 @@ def run(self): ), ext_modules=[ + # The full and correct module name is required here because + # setuptools needs to resolve the name to find the built file + # and copy it into the source tree. (Because yes, editable install + # means that the install should point to the source tree, which + # means the .sos need to also be there alongside the python files). Extension('opentimelineio._otio', sources=[]), Extension('opentimelineio._opentime', sources=[]), ],