Commit graph

353 commits

Author SHA1 Message Date
bors[bot] 550473fb1d
Merge #3031
3031: mangle exported functions for PyPy r=davidhewitt a=mattip

I run HEAD of PyO3 with HEAD of some PyPy branches, and noticed that the py3.10 branch (which implements python3.10) [fails to properly build](https://github.com/pypy/binary-testing/actions/runs/4334873617/jobs/7569059852#step:6:179). The failure was a missing export:
```
 /home/runner/work/binary-testing/binary-testing/pyo3/src/exceptions.rs:715: \
    undefined reference to `PyExc_EncodingWarning'
          collect2: error: ld returned 1 exit status
```

So I grepped around in the code for `Py_3_10` to see what new functions were added and found a few that needed PyPy-specific exports.

Co-authored-by: Matti Picus <matti.picus@gmail.com>
2023-03-10 09:39:54 +00:00
Matti Picus 232f9fb8ab add newsfragment 2023-03-10 10:16:24 +11:00
Antoine Romero-Romero a629e8267a feat: add #[pyo3(get, set)] for Cell 2023-03-09 23:09:30 +00:00
Adam Reichold 39d19113fa Remove stale references to tox.ini from template substitution scripts. 2023-03-05 09:17:34 +01:00
David Hewitt 7a2b1f0e13 fix non_snake_case lint for #[pyfunction] generated code 2023-02-28 08:44:17 +00:00
David Hewitt 226bf97ec0 Fix clippy::redundant_closure lint firing for pyfunction defaults 2023-02-27 22:10:06 +00:00
Adam Reichold 9534749d8b Add GILProtected synchronization primitive replacement and use it for LazyTypeObjectInner. 2023-02-23 09:38:02 +01:00
bors[bot] bbaceb88b4
Merge #2899
2899: RFC: Provide a special purpose FromPyObject impl for byte slices r=davidhewitt a=adamreichold

This enables efficiently and safely getting a byte slice from either bytes or byte arrays.

The main issue I see here is discoverability, i.e. should this be mention in the docs of `PyBytes` and `PyByteArray` or in the guide?

It is also not completely clear whether this really _fixes_ the issue.

Closes #2888 

Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
2023-02-22 22:13:56 +00:00
Adam Reichold de79ebc5f8 Provide a special purpose FromPyObject impl to efficiently and safely get a byte slice from either bytes or byte arrays. 2023-02-22 22:07:59 +01:00
David Hewitt f239d2d075 allow create_exception! to place the exception in a dotted.module 2023-02-22 20:08:53 +00:00
bors[bot] bd07ecc91d
Merge #2952
2952: Fix allow_threads segfault r=davidhewitt a=OliverBalfour

Please see the corresponding issue **#2951** for details. This PR adds the failing test from the issue and then a fix for it. The fix simply calls `ReferencePool::update_counts` at the end of `allow_threads` to ensure objects aren't accidentally deleted too soon.

Co-authored-by: Oliver Balfour <oliver.leo.balfour@gmail.com>
2023-02-21 08:46:06 +00:00
Oliver Balfour 83f5fa2902 update reference pool counts at the end of allow_threads to avoid use-after-free 2023-02-21 08:44:48 +00:00
Azat Ibrakov 9f7368922f docs: fix typo in method name 2023-02-18 22:02:05 +01:00
bors[bot] 3b2c175f8d
Merge #2947
2947: change PyModule::add_class to return an error if class creation fails r=adamreichold a=davidhewitt

Related to #2942 

At the moment there are panics deep in the `#[pyclass]` machinery when initialising the type fails. This PR adjusts a number of these functions to return `PyResult` instead, so that we can handle the error more appropriately further down the pipeline.

For example, take the following snippet:

```rust
#[pyclass(extends = PyBool)]
struct ExtendsBool;

#[pymodule]
fn pyo3_scratch(_py: Python, m: &PyModule) -> PyResult<()> {
    m.add_class::<ExtendsBool>()?;
    Ok(())
}
```

Currently, importing this module will fail with a panic:

```
TypeError: type 'bool' is not an acceptable base type
thread '<unnamed>' panicked at 'An error occurred while initializing class ExtendsBool', /Users/david/Dev/pyo3/src/pyclass.rs:412:5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
pyo3_runtime.PanicException: An error occurred while initializing class ExtendsBool
```

After this PR, this import still fails, but with a slightly cleaner, more Pythonic error:

```
TypeError: type 'bool' is not an acceptable base type

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "/Users/david/.virtualenvs/pyo3/lib/python3.10/site-packages/pyo3_scratch/__init__.py", line 1, in <module>
    from .pyo3_scratch import *
RuntimeError: An error occurred while initializing class ExtendsBool
```

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
Co-authored-by: Adam Reichold <adam.reichold@t-online.de>
2023-02-18 16:12:17 +00:00
bors[bot] c858ced8d4
Merge #2944
2944: optimize sequence conversion for list and tuple r=adamreichold a=davidhewitt

closes #2943 

Avoid using `PyObject_IsInstance` for checking if lists or tuples are sequences, as we know they are always sequences.

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2023-02-15 23:16:35 +00:00
David Hewitt ff48b0f18e optimize sequence conversion for list and tuple 2023-02-15 08:28:29 +00:00
David Hewitt 40709db801 optimize mapping conversion for dict 2023-02-15 08:27:18 +00:00
David Hewitt 00ddd21535 change PyModule::add_class to return an error if class creation fails 2023-02-14 22:08:35 +00:00
messense 2ac6006ec8
Disable default features of chrono
To avoid bringing `time` v0.1.x into dependency graph, see https://github.com/time-rs/time/issues/293
2023-02-09 21:27:31 +08:00
David Hewitt 92cca896de release notes for 0.18.1 2023-02-07 21:38:07 +00:00
David Hewitt d67a8dc0a1 link against pythonXY_d.dll for debug Python on Windows 2023-02-07 07:23:17 +00:00
bors[bot] 806eed5b07
Merge #2914
2914: correct ffi definition of PyIter_Check r=davidhewitt a=davidhewitt

Closes #2913 

It looks like what is happening is that PyO3 was relying on an outdated macro form of `PyIter_Check` which is now a CPython implementation detail, which would explain why it was behaving inconsistently on different platforms (likely due to differences in linkers / implementations).

The test I've pushed succeeds, but fails to compile due to a hygiene bug! I'm done for tonight so I'll take a look at that soon and then rebase this after.

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2023-02-03 20:51:15 +00:00
David Hewitt 5bab0e9409 use simplified PyIter_Check on CPython 3.7 2023-02-03 07:55:44 +00:00
bors[bot] 141cbeaa2c
Merge #2912
2912: Add `PyDict.update()` and `PyDict.update_if_missing()` r=davidhewitt a=samuelcolvin

Fix #2910

Note, I'd also be happy to remove the `override_` argument from merge and perhaps rename it to `update_missing` or similar to give a cleaner API. LMK what you think.

Please consider adding the following to your pull request:
 - [x] an entry for this PR in newsfragments
 - [x] docs to all new functions and / or detail in the guide
 - [x] tests for all new or changed functions


Co-authored-by: Samuel Colvin <s@muelcolvin.com>
2023-02-03 06:32:52 +00:00
Samuel Colvin c09dfcd4e0 add PyDict.update() and PyDict.update_if_missing() 2023-02-03 06:32:01 +00:00
bors[bot] cb38ff0111
Merge #2889
2889: Added support for PyErr_WriteUnraisable r=davidhewitt a=mitsuhiko

Fixes #2884

Co-authored-by: Armin Ronacher <armin.ronacher@active-4.com>
2023-01-29 20:28:00 +00:00
Armin Ronacher 066880e7d5 Added support for PyErr_WriteUnraisable 2023-01-29 20:01:22 +00:00
David Hewitt f4953224d8 correct ffi definition of PyIter_Check 2023-01-29 19:43:33 +00:00
messense f8e2a26439
Warn about unknown config keys in PYO3_CONFIG_FILE 2023-01-29 10:49:27 +08:00
bors[bot] d118ee3a73
Merge #2923 #2924
2923: hygiene: fix `#[pymethods(crate = "...")]` r=davidhewitt a=davidhewitt

Got to the bottom of the hygiene issue in test of #2914 

Turns out that `#[pymethods] #[pyo3(crate = "...")]` works, but `#[pymethods(crate = "...")]` was ignoring the argument.

Added a tweak to fix this and a snippet in the hygiene test (which fails on `main`). 

2924: remove unneeded into_iter calls r=davidhewitt a=davidhewitt

Clippy complaining about these to me this morning locally.

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2023-01-27 09:31:20 +00:00
bors[bot] 083dd5fe29
Merge #2904 #2921
2904: refactor docstring generation code r=mejrs a=davidhewitt

As a first step towards #2866 this is a tweak to the macro code which generates Python docstrings. This PR refactors the behaviour so that instead of always creating a `concat!` expression to generate a nul-terminated string, this will only happen if a Rust 1.54+ macro doc is present (e.g. `#[doc = include_str!(...)]`).

The default case now just collects all the `#[doc]` attributes into a single string.

This should make it easier to factor out the `text_signature` formatting, and avoids wasting compile time invoking the `concat!` macro when not necessary.

2921: Check to see if object is `None` before traversing r=davidhewitt a=neachdainn

Closes #2915

When using the C API directly, the intended way to call `visitproc` is via the `Py_VISIT` macro, which checks to see that the provided pointer is not null before passing it along to `visitproc`. Because PyO3 isn't using the macro, it needs to manually check that the pointer isn't null. Without this check, calling `visit.call(&obj)` where `let obj = None;` will segfault.


Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
Co-authored-by: Nate Kent <nate@nkent.net>
2023-01-27 07:52:03 +00:00
Samuel Colvin 3c9ace03d8 add Ellipsis() and is_ellipsis() methods, fix #2906 2023-01-27 06:40:02 +00:00
David Hewitt 5667a095d6 hygiene: fix #[pymethods(crate = "...")] 2023-01-27 06:34:12 +00:00
Nate Kent f38841a8e2
Check to see if object is None before traversing
Closes #2915

When using the C API directly, the intended way to call `visitproc` is
via the `Py_VISIT` macro, which checks to see that the provided pointer
is not null before passing it along to `visitproc`. Because PyO3 isn't
using the macro, it needs to manually check that the pointer isn't null.
Without this check, calling `visit.call(&obj)` where `let obj = None;`
will segfault.
2023-01-26 15:55:58 -08:00
David Hewitt 586fed2c4b send errors in __releasebuffer__ to sys.unraisablehook 2023-01-19 19:10:06 +00:00
David Hewitt 224a4160b4 release: 0.18.0 2023-01-17 19:04:30 +00:00
Sunyeop Lee 8026f3521e Improve derive(FromPyObject) to apply intern! when applicable 2023-01-15 13:39:06 +00:00
David Hewitt 8f48d157d6 deprecate required arguments after option arguments without signature 2023-01-15 10:17:20 +00:00
messense a7a9daed24
Add a changelog entry for #2875 2023-01-12 14:00:53 +08:00
Gilad Naaman 3e4cf7843a Relax indexmap dependency 2023-01-02 09:28:27 +02:00
bors[bot] 8af48bbb53
Merge #2796
2796: Forward cfgs on pyclass fields to the method defs r=davidhewitt a=mejrs

With this and the cfg_attr PR, I don't need cfg_eval at all anymore :)


- [x] needs some more tests

Co-authored-by: mejrs <>
2022-12-29 16:28:26 +00:00
mejrs 530c5b3193 Fix changelog 2022-12-29 15:13:38 +01:00
mejrs 8f51142013 Add changelog 2022-12-28 23:13:55 +01:00
bors[bot] cedb5aecb2
Merge #2843
2843: remove functionality deprecated in 0.16 r=davidhewitt a=davidhewitt

Simple cleanup to remove all functionality marked deprecated in the 0.16 releases.

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-12-28 12:24:59 +00:00
David Hewitt f2608a923c remove functionality deprecated in 0.16 2022-12-28 12:23:53 +00:00
bors[bot] c2adf14f69
Merge #2842
2842: Stop leaking in `new_closure` r=adamreichold a=davidhewitt

This is a rebase of #2690 which simplifies the `MaybeLeaked` abstraction from that PR with just `Cow<'static, CStr>`.

This enabled me to annotate with `FIXME` all the places where we still leak; I wonder if we could potentially use `GILOnceCell` in future and statics to avoid those. As those callsities are in `#[pyclass]` and `#[pyfunction]` these are effectively in statics anyway, but it would be nice to tidy up.


Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-12-28 08:13:58 +00:00
David Hewitt 1e8206c0b8 Stop leaking in new_closure 2022-12-28 07:51:50 +00:00
bors[bot] 31c42cc2c8
Merge #2838
2838: pypy: re-enable PyFunction on 3.8+ r=davidhewitt a=davidhewitt

PyPy [fixed the crashes associated with `PyFunction](https://foss.heptapod.net/pypy/pypy/-/issues/3776#note_191626)  in PyPy 7.3.10 (for 3.8+) - which I think is to be released shortly. So I think we should re-enable this API and treat it as a PyPy bug which users can mitigate by updating their PyPy.

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-12-27 21:40:57 +00:00
David Hewitt f24b1370b6
correct changelog for 2772 2022-12-27 20:14:21 +00:00
David Hewitt 5fcc8741e0 add changelog for 2772 2022-12-27 16:19:18 +00:00
David Hewitt 24032fe110 pypy: re-enable PyFunction on 3.8+ 2022-12-27 14:32:43 +00:00
bors[bot] 75ca1b2823
Merge #2398
2398: Add `GILOnceCell::get_or_try_init` r=mejrs a=a1phyr

This is similar to [`OnceCell::get_or_try_init`](https://docs.rs/once_cell/latest/once_cell/sync/struct.OnceCell.html#method.get_or_try_init) and is very useful for fallible initialization.

Co-authored-by: Benoît du Garreau <bdgdlm@outlook.com>
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-12-26 21:18:23 +00:00
Benoît du Garreau 01fcfedbe5 Add GILOnceCell::get_or_try_init 2022-12-26 20:28:18 +00:00
David Hewitt 75a120ced6 newsfragments: remove incorrect fragment 2022-12-26 20:26:06 +00:00
bors[bot] e5cf1cb971
Merge #2826
2826: ci: run checks for all platforms on PR r=adamreichold a=davidhewitt

I've been struggling a little to merge PRs with the new bors workflow; overall I think the lighter PR workflow is better but the number of combinations of older pythons / platforms not covered makes it easy for the bors step to fail.

This PR tries to improve the situation by merging the `clippy` and `check-target` job and running it for all supported platforms on PR. Hopefully if these are green, then there's high likelihood that tests will build and should pass unless there's logic errors.

While creating this I found a build error on PyPy which made me notice we can support `PyList::get_item_unchecked` for PyPy, so I added it.

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-12-25 21:02:22 +00:00
David Hewitt 710c895d01 ci: run checks for all platforms on PR 2022-12-25 20:02:21 +00:00
bors[bot] e5ae4e266b
Merge #2784 #2827
2784: Automatically generate `__text_signature__` for all functions r=davidhewitt a=davidhewitt

This PR makes it so that PyO3 generates `__text_signature__` by default for all functions. It also introduces `#[pyo3(text_signature = false)]` to disable the built-in generation.

There are a few limitations which we can improve later:
 - All default values are currently set to `...`. I think this is ok because `.pyi` files often do the same. Maybe for numbers, strings, `None` and `True`/`False` we could render these in a future PR.
 - No support for `#[new]` yet.

Alternative design ideas:
- Only autogenerate for methods with `#[pyo3(signature = (...))]` annotation. I started with this, and then decided it made sense to do it for everything.
- Opt-out with `#[pyo3(text_signature = None)]`. This is slightly harder to parse in the macro, but matches the final result in Python better, so if this looks preferable to others, I can change from `text_signature = false` to `text_signature = None`.

There's some small tidying up / refactoring to do before this merges (happy to take suggestions on this), however the general logic, design and docs are ready for review.


2827: pypy: enable `PyList::get_item_unchecked` r=adamreichold a=davidhewitt

Split out from #2826. Approved previously as part of that review.

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-12-25 19:45:50 +00:00
David Hewitt 010dd509d7 pypy: enable PyList::get_item_unchecked 2022-12-25 08:45:36 +00:00
David Hewitt 5039fd746a add automatic text signature generation 2022-12-24 09:43:02 +00:00
bors[bot] 203ac5d778
Merge #2811
2811: adjust vectorcall symbols for pypy r=davidhewitt a=davidhewitt

Closes #2738

Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-12-17 11:08:00 +00:00
David Hewitt 4a6b24ea07 adjust vectorcall symbols for pypy 2022-12-17 11:07:30 +00:00
David Hewitt 33871b7aea allow **kwargs to take arguments which conflict with positional-only parameters 2022-12-17 07:22:28 +00:00
David Hewitt 3295e35a4b accept any iterator for PySet::new and PyFrozenSet::new 2022-12-04 09:54:34 +00:00
ijl d5a31706c6 Define _PyErr_ChainExceptions() FFI for CPython
This appears to be the only way to chain exceptions via the FFI. It
was introduced prior to CPython 3.7. It has some description of usage
in PEP 490. There was a discussion of whether it should be made stable
in BPO 44938.
2022-12-01 15:25:56 +00:00
David Hewitt 97487ffbb5 add abi3-py311 feature 2022-11-23 08:08:12 +00:00
Georg Brandl cbae47d171 PySlice: fix isize->long truncation in initialization
Fixes #2768
2022-11-22 12:04:32 +01:00
David Hewitt 8ca41be87b
Merge pull request #2749 from PyO3/2748-fix
Fix being able to call arg-less `#[new]` with any args from Python
2022-11-20 11:39:42 +00:00
Georg Brandl ea9da80ab1 macros: fix the check for applying METH_NOARGS
to only consider the Python argument list.

Fixes #2750
2022-11-20 09:00:42 +01:00
Georg Brandl 2a630a2a52 Fix being able to call arg-less #[new] with any args from Python
Fixes #2748
2022-11-20 08:25:19 +01:00
Georg Brandl 249c0209fd Add {Py,PyAny}::downcast_unchecked to replace try_from_unchecked calls 2022-11-18 07:00:40 +01:00
Georg Brandl 7d4dfc32b3 PyAny::downcast(): relax lifetime bounds 2022-11-18 07:00:40 +01:00
Georg Brandl c489809938 Py/PyAny: deprecate cast_as() in favor of downcast()
They are (practically) identical on PyAny, and `downcast()` is the more
useful name.
2022-11-18 07:00:40 +01:00
Georg Brandl 1d20f2a531
Export warning classes and add PyErr::warn_explicit() (#2742) 2022-11-17 19:30:48 +01:00
Chih Wang d060a19303
Add support for std::num::NonZero integer types (#2730) 2022-11-13 10:54:55 +00:00
messense dee791de90
pyo3-build-config: rebuild when PYO3_ENVIRONMENT_SIGNATURE value changed 2022-11-09 20:28:18 +08:00
David Hewitt 4b7e0ee5b4
Merge pull request #2685 from alex/type-error
Use a TypeError, rather than a ValueError, when refusing to treat a str as a Vec
2022-11-09 07:36:40 +00:00
Itamar Turner-Trauring 6746ff8216
Python 3.7 support for PyCodeObject. (#2726)
* Python 3.7 support for PyCodeObject.

Co-authored-by: Itamar Turner-Trauring <itamar@pythonspeed.com>
2022-11-08 21:06:05 +00:00
Alex Gaynor f7a487b809
Use a TypeError, rather than a ValueError, when refusing to treat a str as a Vec
This is far more consistent with how these exceptions are usually used
2022-11-07 07:48:13 -05:00
Bruno Kolenbrander 6766d9f93b
Merge pull request #2686 from dalcde/closure-name-doc
Support passing name and doc to new_closure.
2022-11-06 17:35:20 +01:00
David Hewitt 548e90fcec release: 0.17.3 2022-11-01 20:47:46 +00:00
messense 736e97556d
Disable PyModule::filename on PyPy 2022-10-31 15:45:50 +08:00
Dexter Chua 9201a7dd48 Support passing name and doc to PyCFunction::new_closure. Fixes #2665 2022-10-29 12:26:09 +08:00
David Hewitt 0bd261c7d1 packaging: support Python 3.11 2022-10-27 07:44:50 +01:00
David Hewitt 8e8b484169
add #[pyo3(signature = (...))] attribute (#2702) 2022-10-25 07:23:21 +01:00
David Hewitt 747d791f1f
introduce trampolines for methods (#2705) 2022-10-25 07:22:36 +01:00
David Hewitt 39a68cf7ac
Merge pull request #2687 from saethlin/main
Avoid calling slice::from_raw_parts with a null pointer
2022-10-20 07:34:39 +01:00
Ben Kimock 7ff5ab770a Avoid calling slice::from_raw_parts with a null pointer 2022-10-18 17:09:27 -04:00
David Hewitt 446c0e82f0
Merge pull request #2692 from mejrs/all
Implement get/set all on pyclass
2022-10-18 21:39:44 +01:00
mejrs 3b687b7012 newsfragment 2022-10-18 21:40:59 +02:00
Georg Brandl 676227d2a1
Make is_instance() and is_subclass() take &PyAny (#2695) 2022-10-18 19:22:23 +02:00
Bruno Kolenbrander 4a04603c2c
Don't use intocallback in method macros (#2664)
* Don't use intocallback in method macros

Co-authored-by: mejrs <>
2022-10-16 10:35:58 +01:00
David Hewitt 125af9b7de
Merge pull request #2676 from PyO3/exact-iter
Add more implementations of ExactSizeIterator when iterating built-in Python data structures.
2022-10-13 21:28:04 +01:00
Adam Reichold f456ed7586 Also relax the PySequence check when extracting fixed-sized arrays. 2022-10-13 09:43:45 +02:00
Adam Reichold cd361dc5cc Add more implementations of ExactSizeIterator when iterating built-in Python data structures. 2022-10-11 18:21:02 +02:00
David Hewitt bd40011e93 release: 0.17.2 2022-10-04 08:13:53 +01:00
Federico Dolce 63f7df905d
Add chrono 0.4 integration (#2612)
Co-authored-by: Ivan Tham <pickfire@riseup.net>
Co-authored-by: David Hewitt <1939362+davidhewitt@users.noreply.github.com>
2022-09-22 09:00:09 +02:00
David Hewitt 81a79778a2
Merge pull request #2631 from PyO3/relax-extract-sequence-pre-0.17
Relax extract_sequence to the status quo before 0.17 was released
2022-09-21 11:52:34 +02:00
David Hewitt a0be791577
Merge pull request #2630 from davidhewitt/option-pyclass-arg
pyfunction: fix compile error for Option<&T> argument with a default
2022-09-21 11:44:55 +02:00
Adam Reichold 0c30cba57a Add changelog entry detailing which behaviour change this does and does not revert. 2022-09-21 09:50:57 +02:00
David Hewitt c445eba28d pyfunction: fix compile error for Option<&T> argument with a default 2022-09-20 15:44:55 +02:00
Mario Rugiero d72989f986
Enable BigInt conversion for PyPy (#2626)
* Enable bigint conversion for PyPy

* Update src/conversions/num_bigint.rs

* Add a changelog entry for PyPy `num-bigint` support

Co-authored-by: messense <messense@icloud.com>
2022-09-20 18:55:14 +08:00
Jonathan Coates 73242f0ee3
Add release notes 2022-09-19 14:21:28 +01:00
David Hewitt bb99c98ec1 use towncrier to generate CHANGELOG 2022-09-08 07:58:53 +01:00