Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
9f71b65
Add pymeos cffi build workflow
Diviloper Apr 12, 2024
47bbf21
Always get meos sources from default branch
Diviloper Apr 12, 2024
4248485
Set working directory of wheel build step
Diviloper Apr 12, 2024
9f48799
Add ld_path to exports before building wheels
Diviloper Apr 12, 2024
5ae066d
Install meos in linux wheel build container
Diviloper Apr 12, 2024
1aff988
Set working directory of build_sdist steps
Diviloper Apr 12, 2024
a24b5ce
Add checkout in build_wheels
Diviloper Apr 12, 2024
c9831c3
Fix cibw linux script
Diviloper Apr 12, 2024
f94a548
Fix test command
Diviloper Apr 12, 2024
409f12c
Add log in sdist
Diviloper Apr 12, 2024
e1bd638
Use proper build command for sdist
Diviloper Apr 12, 2024
307a7a3
Install build module
Diviloper Apr 12, 2024
40d16f6
Fix artifact path for sdist
Diviloper Apr 12, 2024
e36559c
Fix wheel artifact folder
Diviloper Apr 12, 2024
d91a95d
Skip PyPy builds on linux
Diviloper Apr 12, 2024
fb14215
Add logs
Diviloper Apr 12, 2024
8b0a835
Update library and include dir functions to check for existence of pa…
Diviloper Apr 12, 2024
48b740f
Merge macOS MEOS steps.
Diviloper Apr 12, 2024
ff28d79
Add QEMU to compile for aarch64
Diviloper Apr 12, 2024
b1bc5e7
Add wheel testing job
Diviloper Apr 12, 2024
2ff1425
Remove LD exports from pytest step
Diviloper Apr 12, 2024
7d9e19a
Add upload to pypi job
Diviloper Apr 12, 2024
1f2c8b2
Remove aarch64 for linux
Diviloper Apr 12, 2024
a539850
Create GitHub Release job
Diviloper Apr 12, 2024
fae8939
Disable musllinux builds
Diviloper Apr 12, 2024
fd9380b
Remove QEMU since no cross-compilation is being done anymore
Diviloper Apr 12, 2024
d4795f9
Copy PROJ data in setup.py when PACKAGE_DATA is set to be able to gen…
Diviloper Apr 13, 2024
76d99f8
Pin PROJ versions and set necessary env variables to add proj data to…
Diviloper Apr 13, 2024
207cbee
Set PROJ_DATA and PROJ_LIB in meos_initialize if they are undefined
Diviloper Apr 13, 2024
2f33bc4
Build json-c from sources to get version 0.17 instead of default vers…
Diviloper Apr 13, 2024
5a53338
Add json-c path to env for linux
Diviloper Apr 13, 2024
b56031c
Fix pypi publish action name
Diviloper Apr 13, 2024
5dd5e0d
Only set PROJ_DATA if proj_data folder exists (only whould exist on a…
Diviloper Apr 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 219 additions & 0 deletions .github/workflows/build_pymeos_cffi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
name: Build PyMEOS CFFI

on:
create:
tags:
- "pymeos-cffi-[0-9]+.[0-9]+.[0-9]+*"

jobs:
build_sdist:
name: Build PyMEOS CFFI source distribution
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Python
uses: actions/setup-python@v5
with:
python-version: 3.8
cache: "pip"

- name: Setup pip
run: |
python -m pip install --upgrade pip
python -m pip install build

- name: Build sdist
working-directory: pymeos_cffi
run: |
python -m build -s
ls -l dist

- uses: actions/upload-artifact@v4
with:
name: pymeos_cffi-sdist
path: ./pymeos_cffi/dist/pymeos_cffi-*.tar.gz

build_wheels:
name: Build PyMEOS CFFI for ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-13, macos-14 ]
include:
- ld_prefix: "/usr/local"
- os: macos-14
ld_prefix: "/opt/homebrew"

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Update brew
if: matrix.os == 'macos-13'
# Necessary to avoid issue with macOS runners. See
# https://github.com/actions/runner-images/issues/4020
run: |
brew reinstall python@3.12 || brew link --overwrite python@3.12
brew reinstall python@3.11 || brew link --overwrite python@3.11
brew update

- name: Get dependencies from homebrew (cache)
uses: tecolicom/actions-use-homebrew-tools@v1
if: runner.os == 'macOS'
with:
tools: cmake libpq proj json-c gsl geos

- name: Get PROJ version
id: proj_version
if: runner.os == 'macOS'
run: |
proj_version=$(brew list --versions proj)
proj_version=${proj_version#* }
echo "proj_version=$proj_version" >> $GITHUB_OUTPUT

- name: Install MEOS
if: runner.os == 'macOS'
run: |
git clone --depth 1 https://github.com/MobilityDB/MobilityDB
mkdir MobilityDB/build
cd MobilityDB/build
cmake .. -DMEOS=on
make -j
sudo make install

- name: Setup Python
uses: actions/setup-python@v5

- name: Install cibuildwheel
run: python -m pip install cibuildwheel==2.17.0

- name: Set PROJ_DATA (macOS)
if: runner.os == 'macOS'
run: |
PROJ_DATA=${{ matrix.ld_prefix }}/Cellar/proj/${{ steps.proj_version.outputs.proj_version }}/share/proj
echo "PROJ_DATA=$PROJ_DATA" >> $GITHUB_ENV

- name: Set PROJ_DATA and JSON-C path (Linux)
if: runner.os == 'Linux'
run: |
PROJ_DATA=/usr/proj81/share/proj
echo "PROJ_DATA=$PROJ_DATA" >> $GITHUB_ENV
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib64" >> $GITHUB_ENV

- name: Build wheels
working-directory: pymeos_cffi
run: |
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${{ matrix.ld_prefix }}/lib
export DYLD_LIBRARY_PATH=$DYLD_LIBRARY_PATH:${{ matrix.ld_prefix }}/lib
export PACKAGE_DATA=1
python -m cibuildwheel --output-dir wheelhouse
env:
# Disable PyPy builds on Linux since shapely has no built distributions for them
# Disable builds on musllinux
# Disable builds in linux architectures other than x86_64
CIBW_SKIP: "pp*-manylinux* *musllinux*"
CIBW_ARCHS_LINUX: "x86_64"
CIBW_ENVIRONMENT_PASS_LINUX: PACKAGE_DATA LD_LIBRARY_PATH PROJ_DATA
CIBW_BEFORE_ALL_LINUX: >
yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm &&
yum -y update &&
yum -y install gcc gcc-c++ make cmake postgresql13-devel proj81-devel geos39-devel gsl-devel &&
git clone --branch json-c-0.17 --depth 1 https://github.com/json-c/json-c &&
mkdir json-c-build &&
cd json-c-build &&
cmake ../json-c &&
make &&
make install &&
git clone --depth 1 https://github.com/MobilityDB/MobilityDB &&
mkdir MobilityDB/build &&
cd MobilityDB/build &&
cmake .. -DMEOS=on -DGEOS_INCLUDE_DIR=/usr/geos39/include/ -DGEOS_LIBRARY=/usr/geos39/lib64/libgeos_c.so -DGEOS_CONFIG=/usr/geos39/bin/geos-config -DPROJ_INCLUDE_DIRS=/usr/proj81/include/ -DPROJ_LIBRARIES=/usr/proj81/lib/libproj.so &&
make -j &&
make install

CIBW_TEST_COMMAND: "python -c \"from pymeos_cffi import meos_initialize, meos_finalize; meos_initialize('UTC'); meos_finalize()\""

- uses: actions/upload-artifact@v4
with:
name: pymeos_cffi-wheels-${{ matrix.os }}
path: ./pymeos_cffi/wheelhouse/*.whl

test_wheels:
name: Test PyMEOS CFFI wheel - Python ${{ matrix.python-version }} on ${{ matrix.os }}
needs: build_wheels
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
python-version: [ "3.8", "3.9", "3.10", "3.11", "3.12" ]
os: [ ubuntu-latest, macos-13, macos-14 ]
exclude:
# Necessary due to issue with macOS runners. See
# https://github.com/actions/setup-python/issues/808
# Can be removed once this PR is merged:
# https://github.com/actions/python-versions/pull/259
- os: macos-14
python-version: "3.8"
- os: macos-14
python-version: "3.9"

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Download wheels
uses: actions/download-artifact@v4
with:
name: pymeos_cffi-wheels-${{ matrix.os }}
path: ./pymeos_cffi_wheels

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: "pip"

- name: Install PyMEOS dependencies
run: |
python -m pip install --upgrade pip
pip install -f ./pymeos_cffi_wheels pymeos_cffi
pip install -r pymeos/dev-requirements.txt

- name: Test PyMEOS with pytest
working-directory: pymeos
run: pytest

upload_pypi:
name: Upload to PyPI
needs: [ test_wheels, build_sdist ]
runs-on: ubuntu-22.04
steps:
- uses: actions/download-artifact@v4
with:
path: ./dist
merge-multiple: true

- uses: pypa/gh-action-pypi-publish@release/v1
with:
user: __token__
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/
skip_existing: true

create_release:
name: Create GitHub Release
needs: [ test_wheels, build_sdist ]
runs-on: ubuntu-22.04
steps:
- uses: actions/download-artifact@v4
with:
path: ./dist
merge-multiple: true

- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: ./dist/*
27 changes: 6 additions & 21 deletions pymeos_cffi/pymeos_cffi/builder/build_pymeos.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import platform
import sys
import os

from cffi import FFI

Expand All @@ -12,27 +11,13 @@


def get_library_dirs():
if sys.platform == "linux":
return ["/usr/local/lib"]
elif sys.platform == "darwin":
if platform.processor() == "arm":
return ["/opt/homebrew/lib"]
else:
return ["/usr/local/lib"]
else:
raise NotImplementedError("Unsupported platform")
paths = ["/usr/local/lib", "/opt/homebrew/lib"]
return [path for path in paths if os.path.exists(path)]


def get_include_dirs():
if sys.platform == "linux":
return ["/usr/local/include"]
elif sys.platform == "darwin":
if platform.processor() == "arm":
return ["/opt/homebrew/include"]
else:
return ["/usr/local/include"]
else:
raise NotImplementedError("Unsupported platform")
paths = ["/usr/local/include", "/opt/homebrew/include"]
return [path for path in paths if os.path.exists(path)]


ffibuilder.set_source(
Expand All @@ -41,7 +26,7 @@ def get_include_dirs():
libraries=["meos"],
library_dirs=get_library_dirs(),
include_dirs=get_include_dirs(),
) # library name, for the linker
)

if __name__ == "__main__": # not when running with setuptools
ffibuilder.compile(verbose=True)
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ def textset_make_modifier(function: str) -> str:

def meos_initialize_modifier(_: str) -> str:
return """def meos_initialize(tz_str: "Optional[str]") -> None:

if "PROJ_DATA" not in os.environ and "PROJ_LIB" not in os.environ:
proj_dir = os.path.join(os.path.dirname(__file__), "proj_data")
if os.path.exists(proj_dir):
# Assume we are in a wheel and the PROJ data is in the package
os.environ["PROJ_DATA"] = proj_dir
os.environ["PROJ_LIB"] = proj_dir

tz_str_converted = tz_str.encode('utf-8') if tz_str is not None else _ffi.NULL
_lib.meos_initialize(tz_str_converted, _lib.py_error_handler)"""

Expand Down
2 changes: 2 additions & 0 deletions pymeos_cffi/pymeos_cffi/builder/templates/functions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import logging
import os

from datetime import datetime, timedelta, date
from typing import Any, Tuple, Optional, List

Expand Down
8 changes: 8 additions & 0 deletions pymeos_cffi/pymeos_cffi/functions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import logging
import os

from datetime import datetime, timedelta, date
from typing import Any, Tuple, Optional, List

Expand Down Expand Up @@ -203,6 +205,12 @@ def meos_get_intervalstyle() -> str:


def meos_initialize(tz_str: "Optional[str]") -> None:
if "PROJ_DATA" not in os.environ and "PROJ_LIB" not in os.environ:
# Assume we are in a wheel and the PROJ data is in the package
proj_dir = os.path.join(os.path.dirname(__file__), "proj_data")
os.environ["PROJ_DATA"] = proj_dir
os.environ["PROJ_LIB"] = proj_dir

tz_str_converted = tz_str.encode("utf-8") if tz_str is not None else _ffi.NULL
_lib.meos_initialize(tz_str_converted, _lib.py_error_handler)

Expand Down
30 changes: 30 additions & 0 deletions pymeos_cffi/setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
import os
import shutil

from setuptools import setup


package_data = []

# Conditionally copy PROJ DATA to make self-contained wheels
if os.environ.get("PACKAGE_DATA"):
print("Copying PROJ data to package data")
projdatadir = os.environ.get(
"PROJ_DATA", os.environ.get("PROJ_LIB", "/usr/local/share/proj")
)
if os.path.exists(projdatadir):
shutil.rmtree("pymeos_cffi/proj_data", ignore_errors=True)
shutil.copytree(
projdatadir,
"pymeos_cffi/proj_data",
ignore=shutil.ignore_patterns("*.txt", "*.tif"),
) # Don't copy .tiff files and their related .txt files
else:
raise FileNotFoundError(
f"PROJ data directory not found at {projdatadir}. "
f"Unable to generate self-contained wheel."
)
package_data.append("proj_data/*")
else:
print("Not copying PROJ data to package data")

setup(
packages=["pymeos_cffi", "pymeos_cffi.builder"],
setup_requires=["cffi"],
include_package_data=True,
package_data={"pymeos_cffi": package_data},
cffi_modules=["pymeos_cffi/builder/build_pymeos.py:ffibuilder"],
)