micro-manager / pymmcore

Python bindings for MMCore, Micro-Manager's device control layer
https://pypi.org/project/pymmcore/
GNU Lesser General Public License v2.1
32 stars 8 forks source link

update build pipeline: simplify ci, move metadata into pyproject, support py312 #89

Closed tlambert03 closed 8 months ago

tlambert03 commented 9 months ago

closes #37

I noticed that issue and spent some time updating the build pipeline here. Might have gotten a little carried away, but here's what this PR does now:

an example build can be seen here: https://github.com/tlambert03/pymmcore/actions/runs/6484564479 ... and in addition to the pytest that gets run by cibuildwheel, I'll download those artifacts and test them on a couple real systems

This lets you build the project with python -m build ... or even with pip install -e . (assuming you have the build deps required)

@marktsuchida, if you're generally supportive of this, I can update the maintainer-notes.md to reflect all the changes made here.

things that could potentially be done as well:

For the next deploy, this PR prepares deployment with pypi trusted publishers (rather than tokens) but @marktsuchida, you would need to set it up as described in that link

tlambert03 commented 9 months ago

also just noticed that you're currently building universal2 wheels, and this builds both x86_64 and arm64, let me know if you'd prefer me to switch the arm64 to a universal wheel

tlambert03 commented 9 months ago

To make it easier to discuss what wheels to keep/change, here's what got shipped for pymmcore v10.4.0.71.0:

cp311-win_amd64
cp311-win32
cp311-manylinux_2_17_x86_64.manylinux2014_x86_64
cp311-macosx_10_9_universal2
cp310-win_amd64
cp310-manylinux_2_17_x86_64.manylinux2014_x86_64
cp310-macosx_10_9_universal2
 cp39-win_amd64
 cp39-win32
 cp39-manylinux_2_17_x86_64.manylinux2014_x86_64
 cp39-manylinux_2_17_i686.manylinux2014_i686
 cp39-macosx_10_9_x86_64
 cp38-win_amd64
 cp38-win32
 cp38-manylinux_2_17_x86_64.manylinux2014_x86_64
 cp38-manylinux_2_17_i686.manylinux2014_i686
 cp38-macosx_10_9_x86_64

and in the artifacts from the last build in this PR, we have:

cp312-win_amd64
cp312-manylinux_2_17_x86_64.manylinux2014_x86_64
cp312-macosx_10_9_x86_64
cp312-macosx_11_0_arm64
cp311-win_amd64
cp311-manylinux_2_17_x86_64.manylinux2014_x86_64
cp311-macosx_10_9_x86_64
cp311-macosx_11_0_arm64
cp310-win_amd64
cp310-manylinux_2_17_x86_64.manylinux2014_x86_64
cp310-macosx_10_9_x86_64
cp310-macosx_11_0_arm64
 cp39-win_amd64
 cp39-manylinux_2_17_x86_64.manylinux2014_x86_64
 cp39-macosx_10_9_x86_64
 cp39-macosx_11_0_arm64
 cp38-win_amd64
 cp38-manylinux_2_17_x86_64.manylinux2014_x86_64
 cp38-macosx_10_9_x86_64
 cp38-macosx_11_0_arm64

let me know what you want changed. (i suspect you might want win32 added back?)

marktsuchida commented 9 months ago

Fantastic! Thanks for knocking off a whole bunch of items from my to-do list (especially the use of ci-buildwheel)!

Would be great if you could update the maintainer notes (also feel free to move notes to source comments where things are now in one place, such as NumPy version selection; also feel free to remove any details that ci-buildwheel now takes care of). It is also fine to remove the smoke test and no-longer-needed Linux script.

There is no need to build Windows 32-bit wheels, since we no longer distribute 32-bit device adapters anyway.

I'm also happy with the single-arch wheels for macOS. The universal2 wheels were something of an accident anyway (I didn't explicitly do anything to build them). I think it is good to follow what NumPy (our only dependency) does when there is no reason to do otherwise, and NumPy currently ships 10_9_x86_64 and 11_0_arm64. Also I hope to ship arm64 Micro-Manager soon, and intend to do this as a separate download rather than trying to distribute fat binaries.

I'll review the details and the binary artifacts more carefully later but all the proposed directions look great.

marktsuchida commented 9 months ago

Thanks also for getting rid of the distutils imports. Another to-do item I had.

tlambert03 commented 9 months ago

ok, updated the notes. Let me know if it all makes sense

tlambert03 commented 9 months ago

i was able to test the artifacts on an intel mac and mac silicon (running the pymmcore-plus test suite)... haven't checked windows/linux yet

tlambert03 commented 8 months ago

tested wheels on windows as well.

marktsuchida commented 8 months ago

Checked cp312 binaries on Win/Mac/Linux; they look good (in particular, weak symbols on macOS look safe). Also checked that the Linux wheel works (Ubuntu 22.04, Python 3.10).

tlambert03 commented 8 months ago

Great!

marktsuchida commented 8 months ago

@tlambert03 Thanks for the updated notes! Everything looks good except for just one thing:

The source (.tar.gz) distribution seems to no longer include the MMDevice and MMCore source files (despite the MANIFEST.in -- not immediately sure why this is). I think the old CI built wheels from the sdist so that the sdist would be verified; I don't think we necessarily need to do that but it would be nice if the build from sdist worked out of the box (provided that SWIG etc. are available).

tlambert03 commented 8 months ago

Will check again, surprised to hear that though! Certainly looked at one point. Will figure out... we can also add check-manifest to be sure https://pypi.org/project/check-manifest/

tlambert03 commented 8 months ago

The source (.tar.gz) distribution seems to no longer include the MMDevice and MMCore source files (despite the MANIFEST.in -- not immediately sure why this is)

ah, if you mean the artifact from ci (which indeed lacks it) ... it's because git checkout there doesn't recurse submodules. locally, it seems to work fine. lemme update. locally, here's what the sdist looks like:

dist/pymmcore-10.4.0.71.1.dev0/
├── LICENSE.txt
├── MANIFEST.in
├── PKG-INFO
├── README.md
├── mmCoreAndDevices
│   ├── MMCore
│   │   ├── AppleHost.h
│   │   ├── CircularBuffer.cpp
│   │   ├── CircularBuffer.h
│   │   ├── ConfigGroup.h
│   │   ├── Configuration.cpp
│   │   ├── Configuration.h
│   │   ├── CoreCallback.cpp
│   │   ├── CoreCallback.h
│   │   ├── CoreProperty.cpp
│   │   ├── CoreProperty.h
│   │   ├── CoreUtils.h
│   │   ├── DeviceManager.cpp
│   │   ├── DeviceManager.h
│   │   ├── Devices
│   │   │   ├── AutoFocusInstance.cpp
│   │   │   ├── AutoFocusInstance.h
│   │   │   ├── CameraInstance.cpp
│   │   │   ├── CameraInstance.h
│   │   │   ├── DeviceInstance.cpp
│   │   │   ├── DeviceInstance.h
│   │   │   ├── DeviceInstanceBase.h
│   │   │   ├── DeviceInstances.h
│   │   │   ├── GalvoInstance.cpp
│   │   │   ├── GalvoInstance.h
│   │   │   ├── GenericInstance.h
│   │   │   ├── HubInstance.cpp
│   │   │   ├── HubInstance.h
│   │   │   ├── ImageProcessorInstance.cpp
│   │   │   ├── ImageProcessorInstance.h
│   │   │   ├── MagnifierInstance.cpp
│   │   │   ├── MagnifierInstance.h
│   │   │   ├── SLMInstance.cpp
│   │   │   ├── SLMInstance.h
│   │   │   ├── SerialInstance.cpp
│   │   │   ├── SerialInstance.h
│   │   │   ├── ShutterInstance.cpp
│   │   │   ├── ShutterInstance.h
│   │   │   ├── SignalIOInstance.cpp
│   │   │   ├── SignalIOInstance.h
│   │   │   ├── StageInstance.cpp
│   │   │   ├── StageInstance.h
│   │   │   ├── StateInstance.cpp
│   │   │   ├── StateInstance.h
│   │   │   ├── XYStageInstance.cpp
│   │   │   └── XYStageInstance.h
│   │   ├── Error.cpp
│   │   ├── Error.h
│   │   ├── ErrorCodes.h
│   │   ├── FrameBuffer.cpp
│   │   ├── FrameBuffer.h
│   │   ├── Host.cpp
│   │   ├── Host.h
│   │   ├── LibraryInfo
│   │   │   ├── LibraryPaths.h
│   │   │   ├── LibraryPathsUnix.cpp
│   │   │   └── LibraryPathsWindows.cpp
│   │   ├── LoadableModules
│   │   │   ├── LoadedDeviceAdapter.cpp
│   │   │   ├── LoadedDeviceAdapter.h
│   │   │   ├── LoadedModule.cpp
│   │   │   ├── LoadedModule.h
│   │   │   ├── LoadedModuleImpl.cpp
│   │   │   ├── LoadedModuleImpl.h
│   │   │   ├── LoadedModuleImplUnix.cpp
│   │   │   ├── LoadedModuleImplUnix.h
│   │   │   ├── LoadedModuleImplWindows.cpp
│   │   │   └── LoadedModuleImplWindows.h
│   │   ├── LogManager.cpp
│   │   ├── LogManager.h
│   │   ├── Logging
│   │   │   ├── GenericEntryFilter.h
│   │   │   ├── GenericLinePacket.h
│   │   │   ├── GenericLogger.h
│   │   │   ├── GenericLoggingCore.h
│   │   │   ├── GenericMetadata.h
│   │   │   ├── GenericPacketArray.h
│   │   │   ├── GenericPacketQueue.h
│   │   │   ├── GenericSink.h
│   │   │   ├── GenericStreamSink.h
│   │   │   ├── Logger.h
│   │   │   ├── Logging.h
│   │   │   ├── Metadata.cpp
│   │   │   ├── Metadata.h
│   │   │   └── MetadataFormatter.h
│   │   ├── MMCore.cpp
│   │   ├── MMCore.h
│   │   ├── MMEventCallback.h
│   │   ├── PluginManager.cpp
│   │   ├── PluginManager.h
│   │   ├── Semaphore.cpp
│   │   ├── Semaphore.h
│   │   ├── Task.cpp
│   │   ├── Task.h
│   │   ├── TaskSet.cpp
│   │   ├── TaskSet.h
│   │   ├── TaskSet_CopyMemory.cpp
│   │   ├── TaskSet_CopyMemory.h
│   │   ├── ThreadPool.cpp
│   │   └── ThreadPool.h
│   └── MMDevice
│       ├── Debayer.cpp
│       ├── Debayer.h
│       ├── DeviceBase.h
│       ├── DeviceThreads.h
│       ├── DeviceUtils.cpp
│       ├── DeviceUtils.h
│       ├── FixSnprintf.h
│       ├── ImageMetadata.h
│       ├── ImgBuffer.cpp
│       ├── ImgBuffer.h
│       ├── MMDevice.cpp
│       ├── MMDevice.h
│       ├── MMDeviceConstants.h
│       ├── ModuleInterface.cpp
│       ├── ModuleInterface.h
│       ├── Property.cpp
│       └── Property.h
├── pymmcore
│   ├── __init__.py
│   ├── __init__.pyi
│   ├── _version.py
│   ├── py.typed
│   └── pymmcore_swig.i
├── pymmcore.egg-info
│   ├── PKG-INFO
│   ├── SOURCES.txt
│   ├── dependency_links.txt
│   ├── requires.txt
│   └── top_level.txt
├── pyproject.toml
├── setup.cfg
├── setup.py
└── tests
    └── test_mmcore.py
tlambert03 commented 8 months ago

ok, I added two things

when building the sdist:

      - name: Build sdist
        run: |
          pip install -U pip build check-manifest
          check-manifest 
          python -m build --sdist

check-manifest ensures that everything that is checked into source (including submodules) is either contained in the sdist, or explicitly excluded either in Manifest.in or in pyproject.toml [tool.check-manifest]. So, provided you like the list above, this will ensure that's always the case.

I also added a check-manifest job as well that should give an early warning that the sdist will fail

marktsuchida commented 8 months ago

Perfect, thanks! Will probably do a release soon after deciding what to do with the few other outstanding PRs/issues.