Skip to content

Commit

Permalink
Merge pull request #50 from zopefoundation/drop-setup-requires
Browse files Browse the repository at this point in the history
Drop using ``setup_requires`` due to constant problems on GHA
  • Loading branch information
dataflake committed Apr 22, 2023
2 parents 8a96d52 + 5d65022 commit eb5ff44
Show file tree
Hide file tree
Showing 12 changed files with 1,373 additions and 130 deletions.
18 changes: 9 additions & 9 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ jobs:
- "3.9"
- "3.10"
- "3.11"
- "3.12.0-alpha.5"
- "3.12.0-alpha.7"
os: [ubuntu-20.04, macos-11]
exclude:
- os: macos-11
Expand Down Expand Up @@ -180,15 +180,15 @@ jobs:
python setup.py build_ext -i
python setup.py bdist_wheel
- name: Install zope.container and dependencies (3.12.0-alpha.5)
if: matrix.python-version == '3.12.0-alpha.5'
- name: Install zope.container and dependencies (3.12.0-alpha.7)
if: matrix.python-version == '3.12.0-alpha.7'
run: |
# Install to collect dependencies into the (pip) cache.
# Use "--pre" here because dependencies with support for this future
# Python release may only be available as pre-releases
pip install --pre .[test]
- name: Install zope.container and dependencies
if: matrix.python-version != '3.12.0-alpha.5'
if: matrix.python-version != '3.12.0-alpha.7'
run: |
# Install to collect dependencies into the (pip) cache.
pip install .[test]
Expand Down Expand Up @@ -232,7 +232,7 @@ jobs:
&& startsWith(github.ref, 'refs/tags')
&& startsWith(runner.os, 'Mac')
&& !startsWith(matrix.python-version, 'pypy')
&& !startsWith(matrix.python-version, '3.12.0-alpha.5')
&& !startsWith(matrix.python-version, '3.12.0-alpha.7')
env:
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
run: |
Expand All @@ -251,7 +251,7 @@ jobs:
- "3.9"
- "3.10"
- "3.11"
- "3.12.0-alpha.5"
- "3.12.0-alpha.7"
os: [ubuntu-20.04, macos-11]
exclude:
- os: macos-11
Expand Down Expand Up @@ -288,8 +288,8 @@ jobs:
with:
name: zope.container-${{ runner.os }}-${{ matrix.python-version }}.whl
path: dist/
- name: Install zope.container 3.12.0-alpha.5
if: ${{ startsWith(matrix.python-version, '3.12.0-alpha.5') }}
- name: Install zope.container 3.12.0-alpha.7
if: ${{ startsWith(matrix.python-version, '3.12.0-alpha.7') }}
run: |
pip install -U wheel setuptools
# coverage has a wheel on PyPI for a future python version which is
Expand All @@ -303,7 +303,7 @@ jobs:
# Python release may only be available as pre-releases
pip install --pre -U -e .[test]
- name: Install zope.container
if: ${{ !startsWith(matrix.python-version, '3.12.0-alpha.5') }}
if: ${{ !startsWith(matrix.python-version, '3.12.0-alpha.7') }}
run: |
pip install -U wheel setuptools
pip install -U coverage
Expand Down
6 changes: 5 additions & 1 deletion .meta.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# https://github.com/zopefoundation/meta/tree/master/config/c-code
[meta]
template = "c-code"
commit-id = "1514f236"
commit-id = "fe63cb4c"

[python]
with-appveyor = true
Expand Down Expand Up @@ -42,8 +42,12 @@ additional-config = [
[manifest]
additional-rules = [
"include *.sh",
"include .readthedocs.yaml",
"include compat.cfg",
"recursive-include docs *.bat",
"recursive-include include/persistent *.h",
"recursive-include include/zope.proxy *.c",
"recursive-include include/zope.proxy *.h",
"recursive-include src *.h",
"recursive-include src *.rst",
"recursive-include src *.zcml",
Expand Down
4 changes: 3 additions & 1 deletion CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
5.1 (unreleased)
================

- Add preliminary support for Python 3.12a5.
- Drop using ``setup_requires`` due to constant problems on GHA.

- Add preliminary support for Python 3.12a7.


5.0 (2023-01-24)
Expand Down
4 changes: 4 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ recursive-include docs Makefile

recursive-include src *.py
include *.sh
include .readthedocs.yaml
include compat.cfg
recursive-include docs *.bat
recursive-include include/persistent *.h
recursive-include include/zope.proxy *.c
recursive-include include/zope.proxy *.h
recursive-include src *.h
recursive-include src *.rst
recursive-include src *.zcml
42 changes: 42 additions & 0 deletions include/persistent/_compat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*****************************************************************************
Copyright (c) 2012 Zope Foundation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE
****************************************************************************/

#ifndef PERSISTENT__COMPAT_H
#define PERSISTENT__COMPAT_H

#include "Python.h"

#define INTERN PyUnicode_InternFromString
#define INTERN_INPLACE PyUnicode_InternInPlace
#define NATIVE_CHECK_EXACT PyUnicode_CheckExact
#define NATIVE_FROM_STRING_AND_SIZE PyUnicode_FromStringAndSize

#define Py_TPFLAGS_HAVE_RICHCOMPARE 0

#define INT_FROM_LONG(x) PyLong_FromLong(x)
#define INT_CHECK(x) PyLong_Check(x)
#define INT_AS_LONG(x) PyLong_AsLong(x)
#define CAPI_CAPSULE_NAME "persistent.cPersistence.CAPI"

#else
#define INTERN PyString_InternFromString
#define INTERN_INPLACE PyString_InternInPlace
#define NATIVE_CHECK_EXACT PyString_CheckExact
#define NATIVE_FROM_STRING_AND_SIZE PyString_FromStringAndSize

#define INT_FROM_LONG(x) PyInt_FromLong(x)
#define INT_CHECK(x) PyInt_Check(x)
#define INT_AS_LONG(x) PyInt_AS_LONG(x)

#endif
156 changes: 156 additions & 0 deletions include/persistent/persistent/cPersistence.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/*****************************************************************************
Copyright (c) 2001, 2002 Zope Foundation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE
****************************************************************************/

#ifndef CPERSISTENCE_H
#define CPERSISTENCE_H

#include "_compat.h"
#include "bytesobject.h"

#include "ring.h"

#define CACHE_HEAD \
PyObject_HEAD \
CPersistentRing ring_home; \
int non_ghost_count; \
Py_ssize_t total_estimated_size;

struct ccobject_head_struct;

typedef struct ccobject_head_struct PerCache;

/* How big is a persistent object?
12 PyGC_Head is two pointers and an int
8 PyObject_HEAD is an int and a pointer
12 jar, oid, cache pointers
8 ring struct
8 serialno
4 state + extra
4 size info
(56) so far
4 dict ptr
4 weaklist ptr
-------------------------
68 only need 62, but obmalloc rounds up to multiple of eight
Even a ghost requires 64 bytes. It's possible to make a persistent
instance with slots and no dict, which changes the storage needed.
*/

#define cPersistent_HEAD \
PyObject_HEAD \
PyObject *jar; \
PyObject *oid; \
PerCache *cache; \
CPersistentRing ring; \
char serial[8]; \
signed state:8; \
unsigned estimated_size:24;

/* We recently added estimated_size. We originally added it as a new
unsigned long field after a signed char state field and a
3-character reserved field. This didn't work because there
are packages in the wild that have their own copies of cPersistence.h
that didn't see the update.
To get around this, we used the reserved space by making
estimated_size a 24-bit bit field in the space occupied by the old
3-character reserved field. To fit in 24 bits, we made the units
of estimated_size 64-character blocks. This allows is to handle up
to a GB. We should never see that, but to be paranoid, we also
truncate sizes greater than 1GB. We also set the minimum size to
64 bytes.
We use the _estimated_size_in_24_bits and _estimated_size_in_bytes
macros both to avoid repetition and to make intent a little clearer.
*/
#define _estimated_size_in_24_bits(I) ((I) > 1073741696 ? 16777215 : (I)/64+1)
#define _estimated_size_in_bytes(I) ((I)*64)

#define cPersistent_GHOST_STATE -1
#define cPersistent_UPTODATE_STATE 0
#define cPersistent_CHANGED_STATE 1
#define cPersistent_STICKY_STATE 2

typedef struct {
cPersistent_HEAD
} cPersistentObject;

typedef void (*percachedelfunc)(PerCache *, PyObject *);

typedef struct {
PyTypeObject *pertype;
getattrofunc getattro;
setattrofunc setattro;
int (*changed)(cPersistentObject*);
void (*accessed)(cPersistentObject*);
void (*ghostify)(cPersistentObject*);
int (*setstate)(PyObject*);
percachedelfunc percachedel;
int (*readCurrent)(cPersistentObject*);
} cPersistenceCAPIstruct;

#define cPersistenceType cPersistenceCAPI->pertype

#ifndef DONT_USE_CPERSISTENCECAPI
static cPersistenceCAPIstruct *cPersistenceCAPI;
#endif

#define cPersistanceModuleName "cPersistence"

#define PER_TypeCheck(O) PyObject_TypeCheck((O), cPersistenceCAPI->pertype)

#define PER_USE_OR_RETURN(O,R) {if((O)->state==cPersistent_GHOST_STATE && cPersistenceCAPI->setstate((PyObject*)(O)) < 0) return (R); else if ((O)->state==cPersistent_UPTODATE_STATE) (O)->state=cPersistent_STICKY_STATE;}

#define PER_CHANGED(O) (cPersistenceCAPI->changed((cPersistentObject*)(O)))

#define PER_READCURRENT(O, E) \
if (cPersistenceCAPI->readCurrent((cPersistentObject*)(O)) < 0) { E; }

#define PER_GHOSTIFY(O) (cPersistenceCAPI->ghostify((cPersistentObject*)(O)))

/* If the object is sticky, make it non-sticky, so that it can be ghostified.
The value is not meaningful
*/
#define PER_ALLOW_DEACTIVATION(O) ((O)->state==cPersistent_STICKY_STATE && ((O)->state=cPersistent_UPTODATE_STATE))

#define PER_PREVENT_DEACTIVATION(O) ((O)->state==cPersistent_UPTODATE_STATE && ((O)->state=cPersistent_STICKY_STATE))

/*
Make a persistent object usable from C by:
- Making sure it is not a ghost
- Making it sticky.
IMPORTANT: If you call this and don't call PER_ALLOW_DEACTIVATION,
your object will not be ghostified.
PER_USE returns a 1 on success and 0 failure, where failure means
error.
*/
#define PER_USE(O) \
(((O)->state != cPersistent_GHOST_STATE \
|| (cPersistenceCAPI->setstate((PyObject*)(O)) >= 0)) \
? (((O)->state==cPersistent_UPTODATE_STATE) \
? ((O)->state=cPersistent_STICKY_STATE) : 1) : 0)

#define PER_ACCESSED(O) (cPersistenceCAPI->accessed((cPersistentObject*)(O)))

#endif
67 changes: 67 additions & 0 deletions include/persistent/ring.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*****************************************************************************
Copyright (c) 2003 Zope Foundation and Contributors.
All Rights Reserved.
This software is subject to the provisions of the Zope Public License,
Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution.
THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
FOR A PARTICULAR PURPOSE
****************************************************************************/

/* Support routines for the doubly-linked list of cached objects.
The cache stores a headed, doubly-linked, circular list of persistent
objects, with space for the pointers allocated in the objects themselves.
The cache stores the distinguished head of the list, which is not a valid
persistent object. The other list members are non-ghost persistent
objects, linked in LRU (least-recently used) order.
The r_next pointers traverse the ring starting with the least recently used
object. The r_prev pointers traverse the ring starting with the most
recently used object.
Obscure: While each object is pointed at twice by list pointers (once by
its predecessor's r_next, again by its successor's r_prev), the refcount
on the object is bumped only by 1. This leads to some possibly surprising
sequences of incref and decref code. Note that since the refcount is
bumped at least once, the list does hold a strong reference to each
object in it.
*/

typedef struct CPersistentRing_struct
{
struct CPersistentRing_struct *r_prev;
struct CPersistentRing_struct *r_next;
} CPersistentRing;


/* The list operations here take constant time independent of the
* number of objects in the list:
*/

/* Add elt as the most recently used object. elt must not already be
* in the list, although this isn't checked.
*/
void ring_add(CPersistentRing *ring, CPersistentRing *elt);

/* Remove elt from the list. elt must already be in the list, although
* this isn't checked.
*/
void ring_del(CPersistentRing *elt);

/* elt must already be in the list, although this isn't checked. It's
* unlinked from its current position, and relinked into the list as the
* most recently used object (which is arguably the tail of the list
* instead of the head -- but the name of this function could be argued
* either way). This is equivalent to
*
* ring_del(elt);
* ring_add(ring, elt);
*
* but may be a little quicker.
*/
void ring_move_to_head(CPersistentRing *ring, CPersistentRing *elt);

0 comments on commit eb5ff44

Please sign in to comment.