Skip to content

Commit

Permalink
attempt to fix wheel building job
Browse files Browse the repository at this point in the history
  • Loading branch information
ariebovenberg committed Jun 17, 2024
1 parent 2e6e53a commit 56e30d5
Show file tree
Hide file tree
Showing 14 changed files with 207 additions and 143 deletions.
129 changes: 62 additions & 67 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,73 +8,68 @@ on:
workflow_dispatch:

jobs:
test-python-version:
name: Test Python ${{ matrix.python-version }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
python-version: [
"3.9",
"3.10",
"3.11",
"3.12",
"3.13-dev",
# FUTURE: pypy builds current fail. Uncomment when fixed.
# Low prio because pure-Python version is available.
# NOTE: pypy/pytest fails sometimes (https://github.com/pypy/pypy/issues/3959)
# "pypy3.9",
# "pypy3.10"
]
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
# test-python-versions:
# name: Test Python ${{ matrix.python-version }}
# runs-on: ubuntu-latest
# strategy:
# fail-fast: false
# matrix:
# python-version: [
# "3.9",
# "3.10",
# "3.11",
# "3.12",
# "3.13-dev",
# ]
# steps:
# - uses: actions/checkout@v4
# - uses: actions-rust-lang/setup-rust-toolchain@v1
# - uses: actions/setup-python@v5
# with:
# python-version: ${{ matrix.python-version }}

- name: "Test Rust"
if: ${{ (matrix.os == 'ubuntu-latest') && (matrix.python-version == '3.12') }}
run: |
cargo test
# - name: "Test Rust"
# if: ${{ (matrix.os == 'ubuntu-latest') && (matrix.python-version == '3.12') }}
# run: |
# cargo test

- name: Install and test
shell: bash
run: |
pip install .
pip install -r requirements/test.txt
pytest tests/
# - name: Install and test
# shell: bash
# run: |
# pip install .
# pip install -r requirements/test.txt
# pytest tests/

Test-os:
name: Test on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
- uses: actions-rust-lang/setup-rust-toolchain@v1
# Test-os:
# name: Test on ${{ matrix.os }}
# runs-on: ${{ matrix.os }}
# strategy:
# fail-fast: false
# matrix:
# os: [ubuntu-latest, windows-latest, macos-latest]
# steps:
# - uses: actions/checkout@v4
# - uses: actions-rust-lang/setup-rust-toolchain@v1

- uses: actions/setup-python@v5
if: ${{ !(matrix.os == 'windows-latest') }}
with:
python-version: '3.12'
# - uses: actions/setup-python@v5
# if: ${{ !(matrix.os == 'windows-latest') }}
# with:
# python-version: '3.12'

# ensure 32-bit target is tested
- uses: actions/setup-python@v5
if: ${{ matrix.os == 'windows-latest' }}
with:
python-version: '3.12'
architecture: x86
# # ensure 32-bit target is tested
# - uses: actions/setup-python@v5
# if: ${{ matrix.os == 'windows-latest' }}
# with:
# python-version: '3.12'
# architecture: x86


- name: Install and test
shell: bash
run: |
pip install -e .
pip install -r requirements/test.txt
pytest tests/
# - name: Install and test
# shell: bash
# run: |
# pip install -e .
# pip install -r requirements/test.txt
# pytest tests/

test-pure-python:
name: Test pure Python version
Expand All @@ -83,14 +78,14 @@ jobs:
fail-fast: false
matrix:
python-version: [
"3.9",
"3.10",
"3.11",
# "3.9",
# "3.10",
# "3.11",
"3.12",
"3.13-dev",
# NOTE: pypy/pytest fails sometimes (https://github.com/pypy/pypy/issues/3959)
"pypy3.9",
"pypy3.10"
# "3.13-dev",
# # NOTE: pypy/pytest fails sometimes (https://github.com/pypy/pypy/issues/3959)
# "pypy3.9",
# "pypy3.10"
]
steps:
- uses: actions/checkout@v4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ jobs:
linux:
runs-on: ubuntu-latest
strategy:
fail-fast: false # TODO: unset
matrix:
target: [x86_64, x86, aarch64, armv7, s390x, ppc64le]
steps:
Expand Down Expand Up @@ -101,11 +102,7 @@ jobs:
- name: Publish to PyPI
run: |
pip install twine
twine upload dist/*
twine upload --non-interactive --skip-existing wheels-*/*
env:
TWINE_UESRNAME: __token__
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
TWINE_REPOSITORY: testpypi
with:
command: upload
args: --non-interactive --skip-existing wheels-*/*
8 changes: 4 additions & 4 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
**Rationale**: Nanosecond precision is the standard for most modern
datetime libraries.

- Unified `(from_)canonical_format` methods with `(from_)common_iso8601` methods
into `(format|parse)_common_iso` methods.
- Unified `[from_]canonical_format` methods with `[from_]common_iso8601` methods
into `[format|parse]_common_iso` methods.

**Rationale**: This cuts down on the number of methods; the performance benefits
aren't worth the extra clutter.
of separate methods aren't worth the clutter.

- Renamed `(from_)(rfc3339|rfc2822)` methods to `(format|parse)_(rfc3339|rfc2822)`.
- Renamed `[from_][rfc3339|rfc2822]` methods to `[format|parse]_[rfc3339|rfc2822]`.

**Rationale**: Consistency with other methods.

Expand Down
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ extension-module = ["pyo3/extension-module"]
name = "benchmarks"
path = "benchmarks/rust/main.rs"

# TODO: replace git repos with proper versions once this fix has
# been released: https://github.com/PyO3/pyo3/issues/4093
# TODO: replace git repos with proper versions once 0.22 is released.
# we're waiting on https://github.com/PyO3/pyo3/issues/4093
[dependencies]
# pyo3-ffi = { version = "^0.21.0", default_features = false, features = ["extension-module"]}
# pyo3 = { version = "^0.21.0", features = ["extension-module"] }
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ It's also **way faster** than other third-party libraries—and usually the stan
[🚀 Changelog](https://whenever.readthedocs.io/en/latest/changelog.html) |
[❓ FAQ](https://whenever.readthedocs.io/en/latest/faq.html) |
[🗺️ Roadmap](#roadmap) |
[💬 Issues & discussions](https://github.com/ariebovenberg/whenever/issues)
[💬 Issues & feedback](https://github.com/ariebovenberg/whenever/issues)

</div>

Expand All @@ -65,7 +65,7 @@ Two points stand out:
```

Note this isn't a bug, but a design decision that DST is only considered
when calculations involve *two different timezones*.
when calculations involve *two* timezones.
If you think this is surprising, you
[are](https://github.com/python/cpython/issues/91618)
[not](https://github.com/python/cpython/issues/116035)
Expand All @@ -76,7 +76,7 @@ Two points stand out:
but there's no way to enforce this in the type system!

```python
# Should this be a naive or aware datetime? Can't tell!
# Does this expect naive or aware? Can't tell!
def schedule_meeting(at: datetime) -> None: ...
```

Expand All @@ -85,12 +85,16 @@ Two points stand out:
There are two other popular third-party libraries, but they don't (fully)
address these issues. Here's how they compare to *whenever* and the standard library:

<div align="center">

| | Whenever | datetime | Arrow | Pendulum |
|-------------------|:--------:|:--------:|:-----:|:--------:|
| DST-safe |||| ⚠️ |
| Typed aware/naive |||||
| Fast |||||

</div>

[**Arrow**](https://pypi.org/project/arrow/)
is probably the most historically popular 3rd party datetime library.
It attempts to provide a more "friendly" API than the standard library,
Expand All @@ -100,7 +104,7 @@ of types to just one (``arrow.Arrow``) means that it's even harder
for typecheckers to catch mistakes.

[**Pendulum**](https://pypi.org/project/pendulum/)
came in the scene in 2016, promising better DST-handling,
arrived on the scene in 2016, promising better DST-handling,
as well as improved performance.
However, it only fixes [*some* DST-related pitfalls](https://dev.arie.bovenberg.net/blog/python-datetime-pitfalls/#datetime-library-scorecard),
and its performance has significantly [degraded over time](https://github.com/sdispater/pendulum/issues/818).
Expand Down
22 changes: 22 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,28 @@ module = [
]
ignore_missing_imports = true

[tool.cibuildwheel]
skip = ["pp*", "*-musllinux_i686"]
test-command = "pytest -s {project}/tests"
test-requires = [
"pytest",
"pytest-benchmark",
"hypothesis",
"pytest-mypy-plugins",
]
environment = { PATH = "$HOME/.cargo/bin:$PATH" }

[tool.cibuildwheel.linux]
before-all = "curl -sSf https://sh.rustup.rs | sh -s -- -y"

[tool.cibuildwheel.windows]
before-all = "rustup target add i686-pc-windows-msvc"
environment = { PATH = "$UserProfile\\.cargo\\bin;$PATH" }

[[tool.cibuildwheel.overrides]]
select = "*-musllinux*"
before-all = "curl -sSf https://sh.rustup.rs | sh -s -- -y && apk install tzdata"

[build-system]
build-backend = "setuptools.build_meta"
requires = ["setuptools", "wheel", "setuptools-rust"]
53 changes: 51 additions & 2 deletions src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -621,7 +621,7 @@ pub(crate) unsafe fn newref<'a>(obj: *mut PyObject) -> &'a mut PyObject {

pub(crate) unsafe fn offset_from_py_dt(dt: *mut PyObject) -> PyResult<i32> {
// OPTIMIZE: is calling ZoneInfo.utcoffset() faster?
let delta = PyObject_CallMethodNoArgs(dt, steal!("utcoffset".to_py()?)).as_result()?;
let delta = methcall0(dt, "utcoffset")?;
defer_decref!(delta);
Ok(PyDateTime_DELTA_GET_DAYS(delta) * 86_400 + PyDateTime_DELTA_GET_SECONDS(delta))
}
Expand Down Expand Up @@ -681,7 +681,7 @@ unsafe fn local_offset(
)
.as_result()?;
defer_decref!(naive);
let aware = PyObject_CallMethodNoArgs(naive, steal!("astimezone".to_py()?)).as_result()?;
let aware = methcall0(naive, "astimezone")?;
defer_decref!(aware);
let kwargs = PyDict_New().as_result()?;
defer_decref!(kwargs);
Expand Down Expand Up @@ -898,6 +898,55 @@ pub(crate) const fn hashmask(hash: Py_hash_t) -> Py_hash_t {
}
}

#[inline]
pub(crate) unsafe fn call1(func: *mut PyObject, arg: *mut PyObject) -> PyReturn {
PyObject_CallOneArg(func, arg).as_result()
}

#[inline]
pub(crate) unsafe fn methcall1(slf: *mut PyObject, name: &str, arg: *mut PyObject) -> PyReturn {
PyObject_CallMethodOneArg(slf, name.to_py()?, arg).as_result()
}

#[inline]
pub(crate) unsafe fn methcall0(slf: *mut PyObject, name: &str) -> PyReturn {
PyObject_CallMethodNoArgs(slf, steal!(name.to_py()?)).as_result()
}

#[inline]
pub(crate) unsafe fn get_dt_tzinfo(dt: *mut PyObject) -> *mut PyObject {
#[cfg(Py_3_10)]
{
PyDateTime_DATE_GET_TZINFO(dt)
}
#[cfg(not(Py_3_10))]
{
let tzinfo = PyObject_GetAttrString(dt, c"tzinfo".as_ptr());
// To keep things consistent with the Py3.10 code above,
// we need to decref it, turning it into a borrowed reference.
// We can assume the parent datetime keeps it alive.
Py_DECREF(tzinfo);
tzinfo
}
}

#[inline]
pub(crate) unsafe fn get_time_tzinfo(dt: *mut PyObject) -> *mut PyObject {
#[cfg(Py_3_10)]
{
PyDateTime_TIME_GET_TZINFO(dt)
}
#[cfg(not(Py_3_10))]
{
let tzinfo = PyObject_GetAttrString(dt, c"tzinfo".as_ptr());
// To keep things consistent with the Py3.10 code above,
// we need to decref it, turning it into a borrowed reference.
// We can assume the parent datetime keeps it alive.
Py_DECREF(tzinfo);
tzinfo
}
}

// from stackoverflow.com/questions/5889238
#[cfg(target_pointer_width = "64")]
#[inline]
Expand Down
10 changes: 4 additions & 6 deletions src/local_datetime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,7 @@ impl OffsetDateTime {
pub(crate) unsafe fn to_local_system(self, py_api: &PyDateTime_CAPI) -> PyResult<Self> {
let dt_original = self.to_py(py_api)?;
defer_decref!(dt_original);
let dt_new =
PyObject_CallMethodNoArgs(dt_original, steal!("astimezone".to_py()?)).as_result()?;
let dt_new = methcall0(dt_original, "astimezone")?;
defer_decref!(dt_new);
Ok(OffsetDateTime::new_unchecked(
Date {
Expand All @@ -81,8 +80,7 @@ impl Instant {
) -> PyResult<OffsetDateTime> {
let dt_utc = self.to_py(py_api)?;
defer_decref!(dt_utc);
let dt_new =
PyObject_CallMethodNoArgs(dt_utc, steal!("astimezone".to_py()?)).as_result()?;
let dt_new = methcall0(dt_utc, "astimezone")?;
defer_decref!(dt_new);
Ok(OffsetDateTime::new_unchecked(
Date {
Expand Down Expand Up @@ -376,7 +374,7 @@ unsafe fn to_tz(slf: *mut PyObject, tz: *mut PyObject) -> PyReturn {
zoned_datetime_type,
..
} = State::for_type(type_);
let zoneinfo = PyObject_CallOneArg(zoneinfo_type, tz).as_result()?;
let zoneinfo = call1(zoneinfo_type, tz)?;
defer_decref!(zoneinfo);
let odt = OffsetDateTime::extract(slf);
let DateTime { date, time } = odt
Expand Down Expand Up @@ -648,7 +646,7 @@ unsafe fn now(cls: *mut PyObject, _: *mut PyObject) -> PyReturn {
)
.as_result()?;
defer_decref!(utc_dt);
let local_dt = PyObject_CallMethodNoArgs(utc_dt, steal!("astimezone".to_py()?)).as_result()?;
let local_dt = methcall0(utc_dt, "astimezone")?;
defer_decref!(local_dt);
OffsetDateTime::new_unchecked(
Date {
Expand Down
Loading

0 comments on commit 56e30d5

Please sign in to comment.