Repository: zhuyifei1999/guppy3 (language: python)

Issue:
Fails to build on Python 3.11 RC2: fatal error: longintrepr.h: No such file or directory
Cannot get this package to build on Python 3.11:

Upstream: <https://github.com/home-assistant/core/pull/74650>


Build output:

```
  Building wheel for guppy3 (setup.py): started
  Building wheel for guppy3 (setup.py): finished with status 'error'
  error: subprocess-exited-with-error
  
  × python setup.py bdist_wheel did not run successfully.
  │ exit code: 1
  ╰─> [96 lines of output]
      running bdist_wheel
      running build
      running build_py
      creating build
      creating build/lib.linux-x86_64-cpython-311
      creating build/lib.linux-x86_64-cpython-311/guppy
      copying guppy/_version.py -> build/lib.linux-x86_64-cpython-311/guppy
      copying guppy/__init__.py -> build/lib.linux-x86_64-cpython-311/guppy
      creating build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/etc.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/xterm.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/IterPermute.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/Cat.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
  Running setup.py clean for guppy3
      copying guppy/etc/RE.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/KanExtension.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/textView.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/Glue.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/FSA.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/RE_Rect.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/Help.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/KnuthBendix.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/Code.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/Descriptor.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/cmd.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/__init__.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      copying guppy/etc/tkcursors.py -> build/lib.linux-x86_64-cpython-311/guppy/etc
      creating build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Exceptions.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Document.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Main.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Latex.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Html.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/SpecNodes.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/FileIO.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Filer.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Tester.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Help.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/DottedTree.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Text.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/XHTML.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/Gsml.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      copying guppy/gsl/__init__.py -> build/lib.linux-x86_64-cpython-311/guppy/gsl
      creating build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Part.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/pbhelp.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Classifiers.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/RefPat.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/UniSet.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Spec.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Doc.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Use.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Console.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Remote.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Monitor.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Prof.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/OutputHandling.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/RM.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/View.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Path.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/RemoteConstants.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/ImpSet.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/Target.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      copying guppy/heapy/__init__.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy
      creating build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_menuleak.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_Classifiers.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_all.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_View.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_OutputHandling.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_gsl.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_RetaGraph.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_heapyc.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_ER.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_Path.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_RefPat.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_Spec.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_dependencies.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_UniSet.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_sf.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/test_Part.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/support.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      copying guppy/heapy/test/__init__.py -> build/lib.linux-x86_64-cpython-311/guppy/heapy/test
      creating build/lib.linux-x86_64-cpython-311/guppy/sets
      copying guppy/sets/test.py -> build/lib.linux-x86_64-cpython-311/guppy/sets
      copying guppy/sets/__init__.py -> build/lib.linux-x86_64-cpython-311/guppy/sets
      running build_ext
      building 'guppy.sets.setsc' extension
      creating build/temp.linux-x86_64-cpython-311
      creating build/temp.linux-x86_64-cpython-311/src
      creating build/temp.linux-x86_64-cpython-311/src/sets
      gcc -pthread -Wsign-compare -DNDEBUG -g -fwrapv -O3 -Wall -fPIC -I/home/runner/work/core/core/venv/include -I/opt/hostedtoolcache/Python/3.11.0-rc.2/x64/include/python3.11 -c src/sets/bitset.c -o build/temp.linux-x86_64-cpython-311/src/sets/bitset.o
      src/sets/bitset.c:7:10: fatal error: longintrepr.h: No such file or directory
          7 | #include "longintrepr.h"
            |          ^~~~~~~~~~~~~~~
      compilation terminated.
      error: command '/usr/bin/gcc' failed with exit code 1
      [end of output]
```

Ref: <https://github.com/cython/cython/issues/4461>


Discussion / hints:
I haven't had time to try to add Python 3.11 compatibility yet. I'll look into this.
This one should be solvable by a simple cython bump
@zhuyifei1999 do you have rough ETA when you'll be able to have a look on the issue? Thanks for any info!
> This one should be solvable by a simple cython bump

guppy doesn't use cython. It's direct C code using CPython API.

> @zhuyifei1999 do you have rough ETA when you'll be able to have a look on the issue? Thanks for any info!

Let me try this weekend.
The frame optimization in Python 3.11 in https://github.com/python/cpython/issues/88756 made it quite a bit more difficult to support it. Guppy needs the ability to read all locals and globals of all stack frames for traversing purposes, and knowing names of variables (the "relate" part of guppy).

Previously this was easy: Every frame will have a Python-visible frame object, so we can traverse the rootstate for frame objects: https://github.com/zhuyifei1999/guppy3/blob/4cb9fcb5d75327544a6875b6caabfdffb70a7e29/src/heapy/rootstate.c#L309-L322

and then let frame object traversal do its thing:
https://github.com/zhuyifei1999/guppy3/blob/4cb9fcb5d75327544a6875b6caabfdffb70a7e29/src/heapy/stdtypes.c#L199-L270

But now I need to do frame attributes as "rootstate" attributes since all the intermediate structs are not Python-visible objects. And It's not just traverse I need to implement (the pre-3.11 I can just trverse to the most recent frame object and it'll recursively traverse its f_back, but now I can't rely on this), but also "relate" (finding names of objects), getattr, and dir()...

I'll keep working on it.

Fix patch:
diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml
index 32ddbf7..d877668 100644
--- a/.github/workflows/workflow.yml
+++ b/.github/workflows/workflow.yml
@@ -13,12 +13,12 @@ jobs:
     name: Build source distribution
     runs-on: ubuntu-latest
     steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
 
       - name: Build sdist
         run: pipx run build --sdist
 
-      - uses: actions/upload-artifact@v2
+      - uses: actions/upload-artifact@v3
         with:
           path: dist/*.tar.gz
 
@@ -27,13 +27,13 @@ jobs:
     needs: build_sdist
     runs-on: ${{ matrix.os }}
     # https://github.com/zhuyifei1999/guppy3/issues/37
-    continue-on-error: ${{ matrix.os == 'windows-2019' && matrix.python-version == '3.9' }}
+    continue-on-error: ${{ (matrix.os == 'windows-latest' || matrix.os == 'macos-latest') && matrix.python-version == '3.10' && matrix.codecov }}
 
     strategy:
       fail-fast: false
       matrix:
-        os: [ubuntu-20.04, windows-2019, macos-10.15]
-        python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"]
+        os: [ubuntu-latest, windows-latest, macos-latest]
+        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
         tracemalloc: [true, false]
         codecov: [true, false]
         sdist: [true, false]
@@ -45,16 +45,16 @@ jobs:
     steps:
     - name: Checkout
       if: ${{ !matrix.sdist }}
-      uses: actions/checkout@v2
+      uses: actions/checkout@v3
     - name: Download sdist
       if: ${{ matrix.sdist }}
-      uses: actions/download-artifact@v2
+      uses: actions/download-artifact@v3
       with:
         name: artifact
         path: dist
 
     - name: Set up Python
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
         python-version: ${{ matrix.python-version }}
 
@@ -103,64 +103,43 @@ jobs:
       shell: bash
       run: bash <(curl -s https://codecov.io/bash)
 
-  build_wheels_native:
+  build_wheels:
     name: Build wheels on ${{ matrix.os }}
     runs-on: ${{ matrix.os }}
     if: github.event_name == 'push'
     strategy:
       matrix:
-        os: [ubuntu-20.04, windows-2019, macos-10.15]
+        os: [ubuntu-latest, windows-latest, macos-latest]
 
     steps:
-      - uses: actions/checkout@v2
-
-      - name: Build wheels
-        uses: pypa/cibuildwheel@v2.3.1
-        env:
-          CIBW_BUILD: cp3{[6789],10}-*
-
-      - uses: actions/upload-artifact@v2
-        with:
-          path: ./wheelhouse/*.whl
-
-  build_wheels_emulated:
-    name: Build wheels on ${{ matrix.os }} ${{ matrix.arch }}
-    runs-on: ${{ matrix.os }}
-    if: github.event_name == 'push'
-    strategy:
-      matrix:
-        os: [ubuntu-20.04]
-        arch: [aarch64, ppc64le, s390x]
-
-    steps:
-      - uses: actions/checkout@v2
+      - uses: actions/checkout@v3
 
       - name: Set up QEMU
-        uses: docker/setup-qemu-action@v1
+        uses: docker/setup-qemu-action@v2
         with:
           platforms: all
 
       - name: Build wheels
-        uses: pypa/cibuildwheel@v2.3.1
+        uses: pypa/cibuildwheel@v2.12.3
         env:
-          CIBW_BUILD: cp3{[6789],10}-*
-          CIBW_ARCHS_LINUX: ${{ matrix.arch }}
+          CIBW_BUILD: cp3{[789],10,11}-*
+          CIBW_ARCHS: all
 
-      - uses: actions/upload-artifact@v2
+      - uses: actions/upload-artifact@v3
         with:
           path: ./wheelhouse/*.whl
 
   upload_pypi:
-    needs: [test_matrix, build_wheels_native, build_wheels_emulated, build_sdist]
+    needs: [test_matrix, build_wheels, build_sdist]
     runs-on: ubuntu-latest
     if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags/v')
     steps:
-      - uses: actions/download-artifact@v2
+      - uses: actions/download-artifact@v3
         with:
           name: artifact
           path: dist
 
-      - uses: pypa/gh-action-pypi-publish@v1.4.2
+      - uses: pypa/gh-action-pypi-publish@release/v1
         with:
           user: __token__
           password: ${{ secrets.pypi_password }}
diff --git a/README.md b/README.md
index 7639f9d..2d0590e 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ Guppy 3 is a fork of Guppy-PE, created by Sverker Nilsson for Python 2.
 
 ## Requirements
 
-You should have Python 3.6, 3.7, 3.8, 3.9, or 3.10. This package is CPython
+You should have Python 3.7, 3.8, 3.9, 3.10, or 3.11. This package is CPython
 only; PyPy and other Python implementations are not supported. Python 2 support
 can be obtained from [guppy-pe](http://guppy-pe.sourceforge.net/) by
 Sverker Nilsson, from which this package is forked.
diff --git a/docs/ProfileBrowser.html b/docs/ProfileBrowser.html
index 21749d4..b11cae8 100644
--- a/docs/ProfileBrowser.html
+++ b/docs/ProfileBrowser.html
@@ -268,4 +268,4 @@ <h3>Table Pane</h3></dt>
 This pane shows a table based on the configuration set
 in the Table menu. The sample number and time stamp
 show in the header.</dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:13 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:12 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/docexample.html b/docs/docexample.html
index 8323991..da89ae9 100644
--- a/docs/docexample.html
+++ b/docs/docexample.html
@@ -204,4 +204,4 @@ <h2>Attribute</h2></dt>
      <dd>
  An attribute named a_nokind, with unspecified kind.
 </dd></dl></dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/docexample.py b/docs/docexample.py
index 30bf0e3..2e58100 100644
--- a/docs/docexample.py
+++ b/docs/docexample.py
@@ -1,5 +1,5 @@
 # Tests generated by: guppy.gsl.Tester
-# Date: Sat Jan 23 02:08:08 2021
+# Date: Sat May 13 06:37:09 2023
 class Tester:
     tests = {}
     def test_example_kind(self, arg):
diff --git a/docs/gsl.html b/docs/gsl.html
index be64021..774a6fb 100644
--- a/docs/gsl.html
+++ b/docs/gsl.html
@@ -180,4 +180,4 @@ <h3> Emacs mode</h3></a>
 Entering GSL mode calls with no arguments the value of the variable
 `gsl-mode-hook', if that value exists and is not nil; see the `Hooks'
 section of the Elisp manual for details.</pre>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/gslexample.html b/docs/gslexample.html
index 8506ad6..e349f21 100644
--- a/docs/gslexample.html
+++ b/docs/gslexample.html
@@ -199,7 +199,7 @@ <h2> Source Code</h2></a>
    <h2> Generated Test Class</h2></a>
   <pre>
 # Tests generated by: guppy.gsl.Tester
-# Date: Sat Jan 23 02:08:08 2021
+# Date: Sat May 13 06:37:09 2023
 class Tester:
     tests = {}
     def test_example_kind(self, arg):
@@ -258,4 +258,4 @@ <h2> Generated Test Class</h2></a>
         t52 = arg.m_alt('abc')
     tests['.tgt.docexample.example_kind'] = test_example_kind
 </pre>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/guppy.html b/docs/guppy.html
index e558aa0..bc7e754 100644
--- a/docs/guppy.html
+++ b/docs/guppy.html
@@ -86,4 +86,4 @@ <h2>Methods</h2></dt>
  There is currently no arguments to this constructor, I may think
 of adding some options in the future, but it has not yet been needed.
 </p></dd></dl></dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/heapy_RootState.html b/docs/heapy_RootState.html
index caa5fe8..2d6a51b 100644
--- a/docs/heapy_RootState.html
+++ b/docs/heapy_RootState.html
@@ -119,4 +119,4 @@ <h3> &lt;frame number&gt;</h3>
 started frame is 0, and in general the most recent frame has a number
 that is the number of frames it has before it in call order.
 </p></dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/heapy_UniSet.html b/docs/heapy_UniSet.html
index 887215f..3780183 100644
--- a/docs/heapy_UniSet.html
+++ b/docs/heapy_UniSet.html
@@ -1484,4 +1484,4 @@ <h2>Mapping</h2></dt><a name='heapy_ER.EquivalenceRelationByDictOwner.-60-3-62-'
 associated with the owner classification of x, though this is not
 currently checked.
 </small></dd></dl></dd></dl></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/heapy_Use.html b/docs/heapy_Use.html
index 8cfe38a..5f05000 100644
--- a/docs/heapy_Use.html
+++ b/docs/heapy_Use.html
@@ -822,4 +822,4 @@ <h2>Attributes</h2></dt>
       <pre>
 &gt;&gt;&gt; hp.doc.heap[0]
 </pre></dd></dl></dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/heapy_tutorial.html b/docs/heapy_tutorial.html
index 948785a..4a2f979 100644
--- a/docs/heapy_tutorial.html
+++ b/docs/heapy_tutorial.html
@@ -83,4 +83,4 @@ <h3>
 &gt;&gt;&gt; hp.iso(x).sp
  0: hp.Root.i0_modules['__main__'].__dict__['x']
 &gt;&gt;&gt; </pre>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/heapyc.html b/docs/heapyc.html
index 5e2e4e8..98b54a1 100644
--- a/docs/heapyc.html
+++ b/docs/heapyc.html
@@ -765,4 +765,4 @@ <h2>Attributes</h2></dt>
 the nodegraph has been used at least once after update, so that it
 will not be cleared too early.
 </dd></dl></dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:08 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/index.html b/docs/index.html
index 1873530..b58797f 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -173,7 +173,7 @@ <h3> Portability aspects</h3>
    <div>
     <ul>
      <li>
- Can be used with an unmodified C Python, back to version 3.6
+ Can be used with an unmodified C Python, back to version 3.7
 AFAIK. Does not depend on any external unix-specific or other
 utilities.
 </li>
@@ -408,4 +408,4 @@ <h2>
    <dd><a href='https://github.com/zhuyifei1999/guppy3/issues'> https://github.com/zhuyifei1999/guppy3/issues</a></dd>
    <dt> The GitHub project page is:</dt>
    <dd><a href='https://github.com/zhuyifei1999/guppy3/'> https://github.com/zhuyifei1999/guppy3/</a></dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:09 2023</div></body></html>
\ No newline at end of file
diff --git a/docs/sets.html b/docs/sets.html
index 2ae2b21..ab46d78 100644
--- a/docs/sets.html
+++ b/docs/sets.html
@@ -500,4 +500,4 @@ <h2>Operator</h2></dt>
  a hash value based on the addresses of the elements.
 
 </dt></dl></dd></dl></dd></dl>
-  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat Jan 23 02:08:08 2021</div></body></html>
\ No newline at end of file
+  <hr>Generated by <a href="https://zhuyifei1999.github.io/guppy3/gsl.html">GSL-HTML 3.0.1</a> on Sat May 13 06:37:08 2023</div></body></html>
\ No newline at end of file
diff --git a/guppy/etc/Glue.py b/guppy/etc/Glue.py
index 23de16e..cb45f34 100644
--- a/guppy/etc/Glue.py
+++ b/guppy/etc/Glue.py
@@ -97,8 +97,10 @@ def pp(self, out=None, short=0):
 
 
 class Share:
+    __slots__ = ('module', 'parent', 'name', 'Clamp', 'setable', 'chgable',
+                 'importedfrom', 'nowrap', 'wrapattr', 'wrapping', 'data',
+                 'owners', 'ispackage', 'recursion', 'preload')
     has_getattr_logging_enabled = False
-    Clamp = None
 
     def __init__(self, module, parent, name, Clamp):
         if parent is None:
@@ -109,8 +111,7 @@ def __init__(self, module, parent, name, Clamp):
         self.module = module
         self.parent = parent
         self.name = name
-        if Clamp is not None:
-            self.Clamp = Clamp
+        self.Clamp = Clamp
 
         self.setable = getattr(Clamp, '_setable_', ())
         if not isinstance(self.setable, tuple):
@@ -423,5 +424,4 @@ def Root():
 """
     share = Share(None, None, '', None)
     r = Owner('').makeInterface({'_name': ''}, share, '')
-    share.root_interface = r
     return r
diff --git a/guppy/heapy/pbhelp.py b/guppy/heapy/pbhelp.py
index c7683db..99f3070 100644
--- a/guppy/heapy/pbhelp.py
+++ b/guppy/heapy/pbhelp.py
@@ -1,4 +1,4 @@
 # AUTOMATICALLY GENERATED BY GENGUPPY
 
-about = b'\x80\x03cguppy.gsl.Text\nRecordingInter\nq\x00)\x81q\x01}q\x02(X\x07\x00\x00\x00appendsq\x03]q\x04(K\x00X\x16\x00\x00\x00Heapy Profile Browser\nq\x05K\x01X\x01\x00\x00\x00\tq\x06K\x02X\x07\x00\x00\x00Versionq\x07K\x01h\x06K\x03X\x04\x00\x00\x000.1\nq\x08K\x04h\x06K\x02X\x06\x00\x00\x00Authorq\tK\x04h\x06K\x03X\x10\x00\x00\x00Sverker Nilsson\nq\nK\x04h\x06K\x02X\x05\x00\x00\x00Emailq\x0bK\x04h\x06K\x03X\x0b\x00\x00\x00sn@sncs.se\nq\x0cK\x04h\x06K\x02X\x07\x00\x00\x00Licenseq\rK\x04h\x06K\x03X\x04\x00\x00\x00MIT\nq\x0eK\x05X\x18\x00\x00\x00Copyright (c) 2005--2008q\x0fK\x06X.\x00\x00\x00S. Nilsson Computer System ABLinkoping, Swedenq\x10K\x07X\x01\x00\x00\x00\nq\x11eX\x0b\x00\x00\x00tag_configsq\x12}q\x13(K\x00X\x08\x00\x00\x00spacing1q\x14K\x0b\x86q\x15X\x04\x00\x00\x00fontq\x16X\x05\x00\x00\x00timesq\x17K\x18X\x04\x00\x00\x00boldq\x18\x87q\x19\x86q\x1a\x86q\x1bK\x02h\x15h\x16h\x17K\x0cX\x04\x00\x00\x00boldq\x1c\x87q\x1d\x86q\x1e\x86q\x1fK\x03h\x15h\x16h\x17K\x0c\x86q \x86q!\x86q"K\x01X\x04\x00\x00\x00tabsq#(G@A\x80\x00\x00\x00\x00\x00X\x06\x00\x00\x00centerq$G@T\x00\x00\x00\x00\x00\x00X\x04\x00\x00\x00leftq%tq&\x86q\'h\x15h\x1e\x87q(K\x04h\'h\x14K\x06\x86q)\x86q*K\x05h)h\x16h\x17K\nX\x06\x00\x00\x00italicq+\x87q,\x86q-\x86q.K\x06h)h\x16h\x17K\n\x86q/\x86q0\x86q1K\x07h)h!\x86q2K\x08h!\x85q3uX\n\x00\x00\x00_gsl_titleq4X\x1b\x00\x00\x00About Heapy Profile Browserq5X\x10\x00\x00\x00_gsl_tk_geometryq6X\x07\x00\x00\x00400x200q7ub.'
-help = b'\x80\x03cguppy.gsl.Text\nRecordingInter\nq\x00)\x81q\x01}q\x02(X\x07\x00\x00\x00appendsq\x03]q\x04(K\x00X\x06\x00\x00\x00Menus\nq\x05K\x01Xr\x00\x00\x00Click on the dotted line at the top of a menu to "tear it off": a separate window containing the menu is created.\nq\x06K\x03X\n\x00\x00\x00File Menu\nq\x07K\x05X\x01\x00\x00\x00\tq\x08K\x06X\x13\x00\x00\x00New Profile Browserq\tK\x05h\x08K\x07X\x15\x00\x00\x00Create a new browser\nq\nK\x08X\x02\x00\x00\x00\t\tq\x0bK\x07X\x15\x00\x00\x00window with the same\nq\x0cK\x08h\x0bK\x07X\x10\x00\x00\x00file as the one\nq\rK\x08h\x0bK\x07X\x16\x00\x00\x00opened in the current\nq\x0eK\x08h\x0bK\x07X\t\x00\x00\x00window. \nq\x0fK\th\x08K\x06X\x0c\x00\x00\x00Open Profileq\x10K\th\x08K\x07X\x14\x00\x00\x00Open a profile data\nq\x11K\x08h\x0bK\x07X\x14\x00\x00\x00file in the current\nq\x12K\x08h\x0bK\x07X\x13\x00\x00\x00window. Data files\nq\x13K\x08h\x0bK\x07X\x14\x00\x00\x00can be created with\nq\x14K\x08h\x0bK\nX\n\x00\x00\x00Stat.dump q\x15K\x07X\x03\x00\x00\x00. \nq\x16K\th\x08K\x06X\x0c\x00\x00\x00Close Windowq\x17K\th\x08K\x07X\x12\x00\x00\x00Close the current\nq\x18K\x08h\x0bK\x07X\x16\x00\x00\x00window (exits from Tk\nq\x19K\x08h\x0bK\x07X\x13\x00\x00\x00if it was the last\nq\x1aK\x08h\x0bK\x07X\x12\x00\x00\x00browser window). \nq\x1bK\th\x08K\x06X\x0b\x00\x00\x00Clear Cacheq\x1cK\th\x08K\x07X\x11\x00\x00\x00Clear the sample\nq\x1dK\x08h\x0bK\x07X\x15\x00\x00\x00cache, releasing its\nq\x1eK\x08h\x0bK\x07X\x12\x00\x00\x00memory. The cache\nq\x1fK\x08h\x0bK\x07X\x16\x00\x00\x00will be automatically\nq K\x08h\x0bK\x07X\x12\x00\x00\x00filled again when\nq!K\x08h\x0bK\x07X\t\x00\x00\x00needed. \nq"K\x08h\x0bK\x0bX\x11\x00\x00\x00This command is aq#K\x07X\x01\x00\x00\x00\nq$K\x08h\x0bK\x0bX\x13\x00\x00\x00kind of temporary /q%K\x07h$K\x08h\x0bK\x0bX\x15\x00\x00\x00experimental feature.q&K\x07h$K\x08h\x0bK\x0bX\x11\x00\x00\x00I think the cacheq\'K\x07h$K\x08h\x0bK\x0bX\x12\x00\x00\x00handling should beq(K\x07h$K\x08h\x0bK\x0bX\x12\x00\x00\x00made automatic andq)K\x07h$K\x08h\x0bK\x0bX\x0b\x00\x00\x00less memoryq*K\x07h$K\x08h\x0bK\x0bX\x0b\x00\x00\x00consuming. q+K\x07h$K\x03X\n\x00\x00\x00Pane Menu\nq,K\x0ch\x08K\x06X\x12\x00\x00\x00Show Control Panelq-K\x0ch\x08K\x07X\x17\x00\x00\x00Show the control panel\nq.K\rh\x0bK\x07X\x07\x00\x00\x00pane. \nq/K\x0eh\x08K\x06X\n\x00\x00\x00Show Graphq0K\x0eh\x08K\x07X\x15\x00\x00\x00Show the graph pane.\nq1K\x0eh\x08K\x06X\n\x00\x00\x00Show Tableq2K\x0eh\x08K\x07X\x15\x00\x00\x00Show the table pane.\nq3K\x03X\x0b\x00\x00\x00Graph Menu\nq4K\x0fh\x08K\x06X\x0c\x00\x00\x00Bars / Linesq5K\x0fh\x08K\x07X\x19\x00\x00\x00Choose whether the graph\nq6K\x10h\x0bK\x07X\x1a\x00\x00\x00should be displayed using\nq7K\x10h\x0bK\x07X\x10\x00\x00\x00bars or lines. \nq8K\x10h\x0bK\x0bX\x1b\x00\x00\x00When using bars, the sampleq9K\x07h$K\x10h\x0bK\x0bX\x19\x00\x00\x00value (size or count) forq:K\x07h$K\x10h\x0bK\x0bX\x1a\x00\x00\x00different kinds of objectsq;K\x07h$K\x10h\x0bK\x0bX\x19\x00\x00\x00will be stacked on top ofq<K\x07h$K\x10h\x0bK\x0bX\x17\x00\x00\x00each other so the totalq=K\x07h$K\x10h\x0bK\x0bX\x1b\x00\x00\x00height represents the totalq>K\x07h$K\x10h\x0bK\x0bX\x17\x00\x00\x00value of a sample. Whenq?K\x07h$K\x10h\x0bK\x0bX\x16\x00\x00\x00using lines, each lineq@K\x07h$K\x10h\x0bK\x0bX\x1a\x00\x00\x00represents the value for aqAK\x07h$K\x10h\x0bK\x0bX\x1a\x00\x00\x00single kind of object. TheqBK\x07h$K\x10h\x0bK\x0bX\x1b\x00\x00\x0010 largest values are shownqCK\x07h$K\x10h\x0bK\x0bX\x1a\x00\x00\x00in each sample point. EachqDK\x07h$K\x10h\x0bK\x0bX\x1c\x00\x00\x00kind has a particular color,qEK\x07h$K\x10h\x0bK\x0bX\x1b\x00\x00\x00choosen arbitrary but it isqFK\x07h$K\x10h\x0bK\x0bX\x19\x00\x00\x00always the same color forqGK\x07h$K\x10h\x0bK\x0bX\x1a\x00\x00\x00the same kind. The remaingqHK\x07h$K\x10h\x0bK\x0bX\x1b\x00\x00\x00kinds, if any, are shown inqIK\x07h$K\x10h\x0bK\x0bX\x07\x00\x00\x00black. qJK\x07h$K\x11h\x08K\x06X\x0c\x00\x00\x00Size / CountqKK\x11h\x08K\x07h6K\x10h\x0bK\x07X\x1b\x00\x00\x00should display the size of\nqLK\x10h\x0bK\x07X\x1d\x00\x00\x00objects of a particular kind\nqMK\x10h\x0bK\x07X\x1c\x00\x00\x00or the number of objects of\nqNK\x10h\x0bK\x07X\x0c\x00\x00\x00that kind. \nqOK\x10h\x0bK\x12X\'\x00\x00\x00(Note that this affects only the graph,qPK\x07h$K\x10h\x0bK\x12X(\x00\x00\x00the table will still choose size or kindqQK\x07h$K\x10h\x0bK\x12X\'\x00\x00\x00as it were choosen in the table menu.) qRK\x07h$K\x03X\x0b\x00\x00\x00Table Menu\nqSK\x13X\x0f\x00\x00\x00Header submenu\nqTK\x14XT\x01\x00\x00This menu has a choice of header for each column of the table. The data of each column is determined by the header of that column, as well as the headers of previous columns. So if you change the first column header (A/B), the data in that column will change as well as the data under the next header (Size/Count) and the ones that follow.\nqUK\x15h\x08K\x16X\x05\x00\x00\x00A / BqVK\x15h\x08K\x17X\x18\x00\x00\x00Use the sample at the A\nqWK\x18h\x0bK\x17X\x1a\x00\x00\x00or B marker in the graph.\nqXK\x18h\x0bK\x17h$K\x18h\x0bK\x14X\x14\x00\x00\x00The kinds of objectsqYK\x17h$K\x18h\x0bK\x14X\x18\x00\x00\x00shown in the table underqZK\x17h$K\x18h\x0bK\x14X\x15\x00\x00\x00this column are takenq[K\x17h$K\x18h\x0bK\x14X\x13\x00\x00\x00from the 10 largestq\\K\x17h$K\x18h\x0bK\x14X\x15\x00\x00\x00sample values at thatq]K\x17h$K\x18h\x0bK\x14X\x18\x00\x00\x00point, in the same orderq^K\x17h$K\x18h\x0bK\x14X\x18\x00\x00\x00as they are shown in theq_K\x17h$K\x18h\x0bK\x14X\x16\x00\x00\x00graph. The ordering inq`K\x17h$K\x18h\x0bK\x14X\x18\x00\x00\x00the graph depends on theqaK\x17h$K\x18h\x0bK\x14X\x17\x00\x00\x00choice of count or sizeqbK\x17h$K\x18h\x0bK\x14X\x12\x00\x00\x00in the graph menu.qcK\x17h$K\x18h\x0bK\x14X\x16\x00\x00\x00However, the table mayqdK\x17h$K\x18h\x0bK\x14X\x12\x00\x00\x00show count or sizeqeK\x17h$K\x18h\x0bK\x14X\x14\x00\x00\x00independent from theqfK\x17h$K\x18h\x0bK\x14X\x15\x00\x00\x00choice in the graph. qgK\x17h$K\x19h\x08K\x16hKK\x19h\x08K\x17X\x1a\x00\x00\x00Show the size or count of\nqhK\x18h\x0bK\x17X\x18\x00\x00\x00the kinds of objects in\nqiK\x18h\x0bK\x17X\x15\x00\x00\x00each row, taken from\nqjK\x18h\x0bK\x17X\x19\x00\x00\x00those choosen in the A /\nqkK\x18h\x0bK\x17X\x0b\x00\x00\x00B column. \nqlK\x19h\x08K\x16X\x0f\x00\x00\x00%A:Tot / %B:TotqmK\x19h\x08K\x17X\x17\x00\x00\x00Show percentage of the\nqnK\x18h\x0bK\x17X\x15\x00\x00\x00Size / Count column,\nqoK\x18h\x0bK\x17X\x16\x00\x00\x00relative to the total\nqpK\x18h\x0bK\x17X\x1a\x00\x00\x00(size or count) at either\nqqK\x18h\x0bK\x17X\x1a\x00\x00\x00the A or B sample point. \nqrK\x19h\x08K\x1aX\x07\x00\x00\x00Cumul /qsK\x19h\x08K\x17X\x19\x00\x00\x00Show either a cumulative\nqtK\x18h\x08K\x1aX\x00\x00\x00\x00quK\x1bX\t\x00\x00\x00A-B / B-AqvK\x18h\x08K\x17X\x18\x00\x00\x00sum of the Size / Count\nqwK\x18h\x0bK\x17X\x1a\x00\x00\x00column, or the difference\nqxK\x18h\x0bK\x17X\r\x00\x00\x00A-B or B-A. \nqyK\x18h\x0bK\x14X\x15\x00\x00\x00The cumulative sum isqzK\x17h$K\x18h\x0bK\x14X\x19\x00\x00\x00taken by summing from theq{K\x17h$K\x18h\x0bK\x14X\x17\x00\x00\x00first table row down toq|K\x17h$K\x18h\x0bK\x14X\x0e\x00\x00\x00the last row. q}K\x17h$K\x19h\x08K\x16hmK\x19h\x08K\x17hnK\x18h\x0bK\x17X\x19\x00\x00\x00previous field, relative\nq~K\x18h\x0bK\x17X\x15\x00\x00\x00to either the A or B\nq\x7fK\x18h\x0bK\x17X\x08\x00\x00\x00total. \nq\x80K\x19h\x08K\x16X\x04\x00\x00\x00Kindq\x81K\x19h\x08K\x17X\x12\x00\x00\x00Shows the kind of\nq\x82K\x18h\x0bK\x17X\x11\x00\x00\x00objects. This is\nq\x83K\x18h\x0bK\x17X\x13\x00\x00\x00currently the only\nq\x84K\x18h\x0bK\x17X\x15\x00\x00\x00alternative for this\nq\x85K\x18h\x0bK\x17X\x17\x00\x00\x00column. The kind shown\nq\x86K\x18h\x0bK\x17X\x19\x00\x00\x00corresponds to the color\nq\x87K\x18h\x0bK\x17X\x13\x00\x00\x00shown in the A / B\nq\x88K\x18h\x0bK\x17X\x1a\x00\x00\x00column. A special kind is\nq\x89K\x18h\x0bK\x17X\x19\x00\x00\x00<Other> which summarizes\nq\x8aK\x18h\x0bK\x17X\x16\x00\x00\x00the remaining data if\nq\x8bK\x18h\x0bK\x17X\x18\x00\x00\x00there were more than 10\nq\x8cK\x18h\x0bK\x17X\x17\x00\x00\x00different kinds in the\nq\x8dK\x18h\x0bK\x17X\t\x00\x00\x00sample. \nq\x8eK\x13X\x12\x00\x00\x00Scrollbar submenu\nq\x8fK\x15h\x08K\x16X\x0f\x00\x00\x00Auto / On / Offq\x90K\x15h\x08K\x17X\x19\x00\x00\x00Choose a scrollbar mode.\nq\x91K\x18h\x0bK\x17X\x1a\x00\x00\x00The usual setting is Auto\nq\x92K\x18h\x0bK\x17X\x1a\x00\x00\x00which shows the scrollbar\nq\x93K\x18h\x0bK\x17X\x13\x00\x00\x00only when needed. \nq\x94K\x03X\x0c\x00\x00\x00Window Menu\nq\x95K\x0bXq\x00\x00\x00This menu lists the names of all open windows. Selecting one brings it to the top, deiconifying it if necessary.\nq\x96K\x03X\n\x00\x00\x00Help Menu\nq\x97K\x1ch\x08K\x06X\x05\x00\x00\x00Aboutq\x98K\x1ch\x08K\x07X#\x00\x00\x00Version, author, email, copyright.\nq\x99K\x1dh\x08K\x06X\x04\x00\x00\x00Helpq\x9aK\x1dh\x08K\x07X\x17\x00\x00\x00Open this help window.\nq\x9bK\x00X\x06\x00\x00\x00Panes\nq\x9cK\x01X\x98\x00\x00\x00There are 3 panes in the main window shown by default. At the top is the Control Panel, at the bottom left the Graph and at the bottom right the Table.\nq\x9dK\x03X\x13\x00\x00\x00Control Panel Pane\nq\x9eK\x1eXl\x00\x00\x00This contains controls for the graph and the markers. It also has a quick-exit button and a collect button.\nq\x9fK\x13X\x13\x00\x00\x00X / Y axis control\nq\xa0K\x14X\xec\x00\x00\x00The two frames in the Control Panel having an X or Y button in the top left corner control each axis of the graph. The X, horizontal, axis shows the sample point. The Y axis shows either the size or count, as choosen in the Graph menu.\nq\xa1K\x1fh\x08K\x16X\x0c\x00\x00\x00X / Y Buttonq\xa2K\x1fh\x08K\x17X\x1c\x00\x00\x00Brings up a menu, currently\nq\xa3K h\x0bK\x17X\x18\x00\x00\x00containing some buttons\nq\xa4K h\x0bK\x17X\x1a\x00\x00\x00that can also be accessed\nq\xa5K h\x0bK\x17X\x18\x00\x00\x00directly in the panel. \nq\xa6K!h\x08K\x16X\x0b\x00\x00\x00Grid buttonq\xa7K!h\x08K\x17X\x1b\x00\x00\x00Select if the graph should\nq\xa8K h\x0bK\x17X\x12\x00\x00\x00show grid lines. \nq\xa9K!h\x08K\x16X\r\x00\x00\x00Range buttonsq\xaaK!h\x08K\x17X\x19\x00\x00\x00Change the range that is\nq\xabK h\x08K\x16huK\x1bX\x05\x00\x00\x00- / +q\xacK h\x08K\x17X\x17\x00\x00\x00shown in the displayed\nq\xadK h\x0bK\x17X\x1a\x00\x00\x00portion of the graph. For\nq\xaeK h\x0bK\x17X\x1c\x00\x00\x00each time + or - is pressed\nq\xafK h\x0bK\x17X\x1a\x00\x00\x00the range will be stepped\nq\xb0K h\x0bK\x17X\x1b\x00\x00\x00up or down in the sequence\nq\xb1K h\x0bK\x17X\x18\x00\x00\x00(1, 2, 5) and multiples\nq\xb2K h\x0bK\x17X\x0b\x00\x00\x00thereoff. \nq\xb3K!h\x08K\x16X\x0b\x00\x00\x00Range fieldq\xb4K!h\x08K\x17X\x1b\x00\x00\x00The current range is shown\nq\xb5K h\x0bK\x17X\x1a\x00\x00\x00here, and a new range can\nq\xb6K h\x0bK\x17X\x19\x00\x00\x00be entered by writing to\nq\xb7K h\x0bK\x17X\x18\x00\x00\x00this field and pressing\nq\xb8K h\x0bK\x17X\x18\x00\x00\x00Enter. The format is an\nq\xb9K h\x0bK\x17X\x14\x00\x00\x00integer that may be\nq\xbaK h\x0bK\x17X\x1a\x00\x00\x00followed by a multiplier,\nq\xbbK h\x0bK\x17X\x1c\x00\x00\x00K, M, G, or T, meaning that\nq\xbcK h\x0bK\x17X\x1a\x00\x00\x00the value is multipled by\nq\xbdK h\x0bK\x17X\x18\x00\x00\x001000, 1E6, 1E9, or 1E12\nq\xbeK h\x0bK\x17X\x1a\x00\x00\x00respectively. The maximum\nq\xbfK h\x0bK\x17X\x0e\x00\x00\x00range is 1T. \nq\xc0K\x13X\x15\x00\x00\x00A / B sample control\nq\xc1K\x14X\x95\x00\x00\x00Each of the frames showing A or B in the top left corner controls one of the sample markers. The current position is shown in the bottom left corner.q\xc2K"X\x86\x00\x00\x00(This is currently not an entry field - TODO - but the marker may be moved long distances by directly dragging it in the Graph frame.)q\xc3K\x14h$K#h\x08K\x16h\xacK#h\x08K\x17X\x1c\x00\x00\x00Step the marker one step to\nq\xc4K$h\x0bK\x17X\x1d\x00\x00\x00the left (-) or to the right\nq\xc5K$h\x0bK\x17X\x06\x00\x00\x00(+). \nq\xc6K$h\x0bK\x14X\x1c\x00\x00\x00The table will be updated toq\xc7K\x17h$K$h\x0bK\x14X\x1b\x00\x00\x00show new data if it was setq\xc8K\x17h$K$h\x0bK\x14X\x1b\x00\x00\x00to show such data that wereq\xc9K\x17h$K$h\x0bK\x14X\x17\x00\x00\x00dependent on the markerq\xcaK\x17h$K$h\x0bK\x14X\x07\x00\x00\x00moved. q\xcbK\x17h$K$h\x0bK\x14X\x1b\x00\x00\x00The graph will show the newq\xccK\x17h$K$h\x0bK\x14X\x17\x00\x00\x00marker position. If theq\xcdK\x17h$K$h\x0bK\x14X\x19\x00\x00\x00marker was outside of theq\xceK\x17h$K$h\x0bK\x14X\x18\x00\x00\x00displayed portion of theq\xcfK\x17h$K$h\x0bK\x14X\x1c\x00\x00\x00graph, the graph will scrollq\xd0K\x17h$K$h\x0bK\x14X\x15\x00\x00\x00so the marker becomesq\xd1K\x17h$K$h\x0bK\x14X\t\x00\x00\x00visible. q\xd2K\x17h$K%h\x08K\x16X\x0c\x00\x00\x00Track buttonq\xd3K%h\x08K\x17X\x1b\x00\x00\x00Press to set the marker to\nq\xd4K$h\x0bK\x17X\x1c\x00\x00\x00the last sample in the file\nq\xd5K$h\x0bK\x17X\x1b\x00\x00\x00and stay at the end as new\nq\xd6K$h\x0bK\x17X\x18\x00\x00\x00samples are added. (New\nq\xd7K$h\x0bK\x17X\x19\x00\x00\x00samples are periodically\nq\xd8K$h\x0bK\x17X\x19\x00\x00\x00read from the end of the\nq\xd9K$h\x0bK\x17X\x1a\x00\x00\x00file when auto-collect is\nq\xdaK$h\x0bK\x17X\x19\x00\x00\x00selected via the Collect\nq\xdbK$h\x0bK\x17X\n\x00\x00\x00button.) \nq\xdcK$h\x0bK\x14X\x1b\x00\x00\x00Tracking is turned off whenq\xddK\x17h$K$h\x0bK\x14X\x16\x00\x00\x00the marker is manuallyq\xdeK\x17h$K$h\x0bK\x14h\xcbK\x17h$K\x13X\x0c\x00\x00\x00Exit button\nq\xdfK\x14XE\x00\x00\x00Exits the program, a shortcut for the Exit command in the File menu.\nq\xe0K\x13X\x0f\x00\x00\x00Collect button\nq\xe1K\x14Xv\x00\x00\x00When selected, the browser will collect new samples from the current file, and will continue to do this periodically.\nq\xe2K"X<\x00\x00\x00Currently it will check the file for new data once a second.q\xe3K\x14h$K\x03X\x0b\x00\x00\x00Graph Pane\nq\xe4K\x0bX\x06\x01\x00\x00This pane shows the currently visible portion of the sample file. It can be scrolled via an horizontal scrollbar. The two markers are shown as buttons labeled A and B above the graph and with lines extending down in the graph. Markers can be moved by the mouse.\nq\xe5K\x07Xt\x00\x00\x00How to move the markers is hopefully quite self evident when tried out but I wrote up some details about it anyway.\nq\xe6K\x13X\x18\x00\x00\x00Marker movement details\nq\xe7K&X\x9d\x04\x00\x00Holding down the mouse button and moving the mouse moves the underlying marker. Klicking the mouse button over a marker without moving the mouse, selects the marker. While it is selected any movement of the mouse within the graph will move the marker with it. Klicking again anywhere in the graph will deselect the marker. If the marker can be moved, the cursor will be an arrow indicating the direction it can be moved, left or right or both. If the marker can not be moved in any direction, the cursor will show a circle or disc. The marker can not move outside the available samples. Moving the mouse outside of the graph also restricts the movement of the mouse, even if the mouse button is pressed. This is intentional so that the marker can be moved longer distances than the mouse can move. Moving the mouse to the right of the graph, the marker can only be moved to the right - moving back the mouse will not move the marker back until the mouse enters the graph area again. Similarly for the left side. Above or below the graph, the mouse will not move the marker at all but will show a circle to indicate that the mouse may be \'recirculated\' to move back into the graph.\nq\xe8K\x03X\x0b\x00\x00\x00Table Pane\nq\xe9K\x0bX\x7f\x00\x00\x00This pane shows a table based on the configuration set in the Table menu. The sample number and time stamp show in the header.\nq\xeaeX\x0b\x00\x00\x00tag_configsq\xeb}q\xec(K\x00X\x08\x00\x00\x00spacing1q\xedK\n\x86q\xeeX\x04\x00\x00\x00fontq\xefX\x05\x00\x00\x00timesq\xf0K\x14X\x04\x00\x00\x00boldq\xf1\x87q\xf2\x86q\xf3\x86q\xf4K\x01h\xeeh\xefh\xf0K\x0c\x86q\xf5\x86q\xf6\x86q\xf7K\x02h\xedK\x06\x86q\xf8h\xf6\x86q\xf9K\x03h\xedK\t\x86q\xfah\xefh\xf0K\x10X\x04\x00\x00\x00boldq\xfb\x87q\xfc\x86q\xfd\x86q\xfeK\x04h\xf6\x85q\xffK\x06(X\x08\x00\x00\x00lmargin1r\x00\x01\x00\x00K$\x86r\x01\x01\x00\x00X\x08\x00\x00\x00lmargin2r\x02\x01\x00\x00K$\x86r\x03\x01\x00\x00h\xf8h\xefh\xf0K\x0cX\x04\x00\x00\x00boldr\x04\x01\x00\x00\x87r\x05\x01\x00\x00\x86r\x06\x01\x00\x00tr\x07\x01\x00\x00K\x07(j\x01\x01\x00\x00j\x03\x01\x00\x00h\xf8h\xf6tr\x08\x01\x00\x00K\x05(X\x04\x00\x00\x00tabsr\t\x01\x00\x00(G@``\x00\x00\x00\x00\x00X\x06\x00\x00\x00centerr\n\x01\x00\x00G@m\x80\x00\x00\x00\x00\x00X\x04\x00\x00\x00leftr\x0b\x01\x00\x00tr\x0c\x01\x00\x00\x86r\r\x01\x00\x00j\x01\x01\x00\x00j\x03\x01\x00\x00h\xf8j\x06\x01\x00\x00tr\x0e\x01\x00\x00K\x08j\r\x01\x00\x00\x85r\x0f\x01\x00\x00K\tj\r\x01\x00\x00h\xf8\x86r\x10\x01\x00\x00K\n(j\x01\x01\x00\x00j\x03\x01\x00\x00h\xf8h\xefh\xf0K\x0cX\x06\x00\x00\x00italicr\x11\x01\x00\x00\x87r\x12\x01\x00\x00\x86r\x13\x01\x00\x00tr\x14\x01\x00\x00K\x0bj\x01\x01\x00\x00j\x03\x01\x00\x00h\xf6\x87r\x15\x01\x00\x00K\x0c(j\t\x01\x00\x00(G@_\x80\x00\x00\x00\x00\x00j\n\x01\x00\x00G@l@\x00\x00\x00\x00\x00j\x0b\x01\x00\x00tr\x16\x01\x00\x00\x86r\x17\x01\x00\x00j\x01\x01\x00\x00j\x03\x01\x00\x00h\xf8j\x06\x01\x00\x00tr\x18\x01\x00\x00K\rj\x17\x01\x00\x00\x85r\x19\x01\x00\x00K\x0ej\x17\x01\x00\x00h\xf8\x86r\x1a\x01\x00\x00K\x0f(j\t\x01\x00\x00(G@X\x00\x00\x00\x00\x00\x00j\n\x01\x00\x00G@d\xc0\x00\x00\x00\x00\x00j\x0b\x01\x00\x00tr\x1b\x01\x00\x00\x86r\x1c\x01\x00\x00j\x01\x01\x00\x00j\x03\x01\x00\x00h\xf8j\x06\x01\x00\x00tr\x1d\x01\x00\x00K\x10j\x1c\x01\x00\x00\x85r\x1e\x01\x00\x00K\x11j\x1c\x01\x00\x00h\xf8\x86r\x1f\x01\x00\x00K\x12j\x01\x01\x00\x00j\x03\x01\x00\x00h\xefh\xf0K\n\x86r \x01\x00\x00\x86r!\x01\x00\x00\x87r"\x01\x00\x00K\x13(j\x01\x01\x00\x00j\x03\x01\x00\x00h\xedK\x08\x86r#\x01\x00\x00j\x06\x01\x00\x00tr$\x01\x00\x00K\x16(j\x00\x01\x00\x00KH\x86r%\x01\x00\x00j\x02\x01\x00\x00KH\x86r&\x01\x00\x00h\xf8j\x06\x01\x00\x00tr\'\x01\x00\x00K\x17(j%\x01\x00\x00j&\x01\x00\x00h\xf8h\xf6tr(\x01\x00\x00K\x15(j\t\x01\x00\x00(G@b`\x00\x00\x00\x00\x00j\n\x01\x00\x00G@m\x00\x00\x00\x00\x00\x00j\x0b\x01\x00\x00tr)\x01\x00\x00\x86r*\x01\x00\x00j%\x01\x00\x00j&\x01\x00\x00h\xf8j\x06\x01\x00\x00tr+\x01\x00\x00K\x18j*\x01\x00\x00\x85r,\x01\x00\x00K\x14j%\x01\x00\x00j&\x01\x00\x00h\xf6\x87r-\x01\x00\x00K\x19j*\x01\x00\x00h\xf8\x86r.\x01\x00\x00K\x1aj\'\x01\x00\x00K\x1bj%\x01\x00\x00j&\x01\x00\x00j\x06\x01\x00\x00\x87r/\x01\x00\x00K\x1c(j\t\x01\x00\x00(G@N\x80\x00\x00\x00\x00\x00j\n\x01\x00\x00G@X\x00\x00\x00\x00\x00\x00j\x0b\x01\x00\x00tr0\x01\x00\x00\x86r1\x01\x00\x00j\x01\x01\x00\x00j\x03\x01\x00\x00h\xf8j\x06\x01\x00\x00tr2\x01\x00\x00K\x1dj1\x01\x00\x00h\xf8\x86r3\x01\x00\x00K\x1eh\xfah\xf6\x86r4\x01\x00\x00K\x1f(j\t\x01\x00\x00(G@a \x00\x00\x00\x00\x00j\n\x01\x00\x00G@j\x80\x00\x00\x00\x00\x00j\x0b\x01\x00\x00tr5\x01\x00\x00\x86r6\x01\x00\x00j%\x01\x00\x00j&\x01\x00\x00h\xf8j\x06\x01\x00\x00tr7\x01\x00\x00K j6\x01\x00\x00\x85r8\x01\x00\x00K!j6\x01\x00\x00h\xf8\x86r9\x01\x00\x00K"j%\x01\x00\x00j&\x01\x00\x00j!\x01\x00\x00\x87r:\x01\x00\x00K#(j\t\x01\x00\x00(G@`\x80\x00\x00\x00\x00\x00j\n\x01\x00\x00G@i@\x00\x00\x00\x00\x00j\x0b\x01\x00\x00tr;\x01\x00\x00\x86r<\x01\x00\x00j%\x01\x00\x00j&\x01\x00\x00h\xf8j\x06\x01\x00\x00tr=\x01\x00\x00K$j<\x01\x00\x00\x85r>\x01\x00\x00K%j<\x01\x00\x00h\xf8\x86r?\x01\x00\x00K&(j\x01\x01\x00\x00j\x03\x01\x00\x00j#\x01\x00\x00h\xf6tr@\x01\x00\x00uX\n\x00\x00\x00_gsl_titlerA\x01\x00\x00X\x1e\x00\x00\x00Help for Heapy Profile BrowserrB\x01\x00\x00ub.'
+about = b'\x80\x04\x95[\x02\x00\x00\x00\x00\x00\x00\x8c\x0eguppy.gsl.Text\x94\x8c\x0eRecordingInter\x94\x93\x94)\x81\x94}\x94(\x8c\x07appends\x94]\x94(K\x00\x8c\x16Heapy Profile Browser\n\x94K\x01\x8c\x01\t\x94K\x02\x8c\x07Version\x94K\x01h\x08K\x03\x8c\x040.1\n\x94K\x04h\x08K\x02\x8c\x06Author\x94K\x04h\x08K\x03\x8c\x10Sverker Nilsson\n\x94K\x04h\x08K\x02\x8c\x05Email\x94K\x04h\x08K\x03\x8c\x0bsn@sncs.se\n\x94K\x04h\x08K\x02\x8c\x07License\x94K\x04h\x08K\x03\x8c\x04MIT\n\x94K\x05\x8c\x18Copyright (c) 2005--2008\x94K\x06\x8c.S. Nilsson Computer System ABLinkoping, Sweden\x94K\x07\x8c\x01\n\x94e\x8c\x0btag_configs\x94}\x94(K\x00\x8c\x08spacing1\x94K\x0b\x86\x94\x8c\x04font\x94\x8c\x05times\x94K\x18\x8c\x04bold\x94\x87\x94\x86\x94\x86\x94K\x02h\x17h\x18h\x19K\x0c\x8c\x04bold\x94\x87\x94\x86\x94\x86\x94K\x03h\x17h\x18h\x19K\x0c\x86\x94\x86\x94\x86\x94K\x01\x8c\x04tabs\x94(G@A\x80\x00\x00\x00\x00\x00\x8c\x06center\x94G@T\x00\x00\x00\x00\x00\x00\x8c\x04left\x94t\x94\x86\x94h\x17h \x87\x94K\x04h)h\x16K\x06\x86\x94\x86\x94K\x05h+h\x18h\x19K\n\x8c\x06italic\x94\x87\x94\x86\x94\x86\x94K\x06h+h\x18h\x19K\n\x86\x94\x86\x94\x86\x94K\x07h+h#\x86\x94K\x08h#\x85\x94u\x8c\n_gsl_title\x94\x8c\x1bAbout Heapy Profile Browser\x94\x8c\x10_gsl_tk_geometry\x94\x8c\x07400x200\x94ub.'
+help = b'\x80\x04\x95v*\x00\x00\x00\x00\x00\x00\x8c\x0eguppy.gsl.Text\x94\x8c\x0eRecordingInter\x94\x93\x94)\x81\x94}\x94(\x8c\x07appends\x94]\x94(K\x00\x8c\x06Menus\n\x94K\x01\x8crClick on the dotted line at the top of a menu to "tear it off": a separate window containing the menu is created.\n\x94K\x03\x8c\nFile Menu\n\x94K\x05\x8c\x01\t\x94K\x06\x8c\x13New Profile Browser\x94K\x05h\nK\x07\x8c\x15Create a new browser\n\x94K\x08\x8c\x02\t\t\x94K\x07\x8c\x15window with the same\n\x94K\x08h\rK\x07\x8c\x10file as the one\n\x94K\x08h\rK\x07\x8c\x16opened in the current\n\x94K\x08h\rK\x07\x8c\twindow. \n\x94K\th\nK\x06\x8c\x0cOpen Profile\x94K\th\nK\x07\x8c\x14Open a profile data\n\x94K\x08h\rK\x07\x8c\x14file in the current\n\x94K\x08h\rK\x07\x8c\x13window. Data files\n\x94K\x08h\rK\x07\x8c\x14can be created with\n\x94K\x08h\rK\n\x8c\nStat.dump \x94K\x07\x8c\x03. \n\x94K\th\nK\x06\x8c\x0cClose Window\x94K\th\nK\x07\x8c\x12Close the current\n\x94K\x08h\rK\x07\x8c\x16window (exits from Tk\n\x94K\x08h\rK\x07\x8c\x13if it was the last\n\x94K\x08h\rK\x07\x8c\x12browser window). \n\x94K\th\nK\x06\x8c\x0bClear Cache\x94K\th\nK\x07\x8c\x11Clear the sample\n\x94K\x08h\rK\x07\x8c\x15cache, releasing its\n\x94K\x08h\rK\x07\x8c\x12memory. The cache\n\x94K\x08h\rK\x07\x8c\x16will be automatically\n\x94K\x08h\rK\x07\x8c\x12filled again when\n\x94K\x08h\rK\x07\x8c\tneeded. \n\x94K\x08h\rK\x0b\x8c\x11This command is a\x94K\x07\x8c\x01\n\x94K\x08h\rK\x0b\x8c\x13kind of temporary /\x94K\x07h&K\x08h\rK\x0b\x8c\x15experimental feature.\x94K\x07h&K\x08h\rK\x0b\x8c\x11I think the cache\x94K\x07h&K\x08h\rK\x0b\x8c\x12handling should be\x94K\x07h&K\x08h\rK\x0b\x8c\x12made automatic and\x94K\x07h&K\x08h\rK\x0b\x8c\x0bless memory\x94K\x07h&K\x08h\rK\x0b\x8c\x0bconsuming. \x94K\x07h&K\x03\x8c\nPane Menu\n\x94K\x0ch\nK\x06\x8c\x12Show Control Panel\x94K\x0ch\nK\x07\x8c\x17Show the control panel\n\x94K\rh\rK\x07\x8c\x07pane. \n\x94K\x0eh\nK\x06\x8c\nShow Graph\x94K\x0eh\nK\x07\x8c\x15Show the graph pane.\n\x94K\x0eh\nK\x06\x8c\nShow Table\x94K\x0eh\nK\x07\x8c\x15Show the table pane.\n\x94K\x03\x8c\x0bGraph Menu\n\x94K\x0fh\nK\x06\x8c\x0cBars / Lines\x94K\x0fh\nK\x07\x8c\x19Choose whether the graph\n\x94K\x10h\rK\x07\x8c\x1ashould be displayed using\n\x94K\x10h\rK\x07\x8c\x10bars or lines. \n\x94K\x10h\rK\x0b\x8c\x1bWhen using bars, the sample\x94K\x07h&K\x10h\rK\x0b\x8c\x19value (size or count) for\x94K\x07h&K\x10h\rK\x0b\x8c\x1adifferent kinds of objects\x94K\x07h&K\x10h\rK\x0b\x8c\x19will be stacked on top of\x94K\x07h&K\x10h\rK\x0b\x8c\x17each other so the total\x94K\x07h&K\x10h\rK\x0b\x8c\x1bheight represents the total\x94K\x07h&K\x10h\rK\x0b\x8c\x17value of a sample. When\x94K\x07h&K\x10h\rK\x0b\x8c\x16using lines, each line\x94K\x07h&K\x10h\rK\x0b\x8c\x1arepresents the value for a\x94K\x07h&K\x10h\rK\x0b\x8c\x1asingle kind of object. The\x94K\x07h&K\x10h\rK\x0b\x8c\x1b10 largest values are shown\x94K\x07h&K\x10h\rK\x0b\x8c\x1ain each sample point. Each\x94K\x07h&K\x10h\rK\x0b\x8c\x1ckind has a particular color,\x94K\x07h&K\x10h\rK\x0b\x8c\x1bchoosen arbitrary but it is\x94K\x07h&K\x10h\rK\x0b\x8c\x19always the same color for\x94K\x07h&K\x10h\rK\x0b\x8c\x1athe same kind. The remaing\x94K\x07h&K\x10h\rK\x0b\x8c\x1bkinds, if any, are shown in\x94K\x07h&K\x10h\rK\x0b\x8c\x07black. \x94K\x07h&K\x11h\nK\x06\x8c\x0cSize / Count\x94K\x11h\nK\x07h8K\x10h\rK\x07\x8c\x1bshould display the size of\n\x94K\x10h\rK\x07\x8c\x1dobjects of a particular kind\n\x94K\x10h\rK\x07\x8c\x1cor the number of objects of\n\x94K\x10h\rK\x07\x8c\x0cthat kind. \n\x94K\x10h\rK\x12\x8c\'(Note that this affects only the graph,\x94K\x07h&K\x10h\rK\x12\x8c(the table will still choose size or kind\x94K\x07h&K\x10h\rK\x12\x8c\'as it were choosen in the table menu.) \x94K\x07h&K\x03\x8c\x0bTable Menu\n\x94K\x13\x8c\x0fHeader submenu\n\x94K\x14XT\x01\x00\x00This menu has a choice of header for each column of the table. The data of each column is determined by the header of that column, as well as the headers of previous columns. So if you change the first column header (A/B), the data in that column will change as well as the data under the next header (Size/Count) and the ones that follow.\n\x94K\x15h\nK\x16\x8c\x05A / B\x94K\x15h\nK\x17\x8c\x18Use the sample at the A\n\x94K\x18h\rK\x17\x8c\x1aor B marker in the graph.\n\x94K\x18h\rK\x17h&K\x18h\rK\x14\x8c\x14The kinds of objects\x94K\x17h&K\x18h\rK\x14\x8c\x18shown in the table under\x94K\x17h&K\x18h\rK\x14\x8c\x15this column are taken\x94K\x17h&K\x18h\rK\x14\x8c\x13from the 10 largest\x94K\x17h&K\x18h\rK\x14\x8c\x15sample values at that\x94K\x17h&K\x18h\rK\x14\x8c\x18point, in the same order\x94K\x17h&K\x18h\rK\x14\x8c\x18as they are shown in the\x94K\x17h&K\x18h\rK\x14\x8c\x16graph. The ordering in\x94K\x17h&K\x18h\rK\x14\x8c\x18the graph depends on the\x94K\x17h&K\x18h\rK\x14\x8c\x17choice of count or size\x94K\x17h&K\x18h\rK\x14\x8c\x12in the graph menu.\x94K\x17h&K\x18h\rK\x14\x8c\x16However, the table may\x94K\x17h&K\x18h\rK\x14\x8c\x12show count or size\x94K\x17h&K\x18h\rK\x14\x8c\x14independent from the\x94K\x17h&K\x18h\rK\x14\x8c\x15choice in the graph. \x94K\x17h&K\x19h\nK\x16hMK\x19h\nK\x17\x8c\x1aShow the size or count of\n\x94K\x18h\rK\x17\x8c\x18the kinds of objects in\n\x94K\x18h\rK\x17\x8c\x15each row, taken from\n\x94K\x18h\rK\x17\x8c\x19those choosen in the A /\n\x94K\x18h\rK\x17\x8c\x0bB column. \n\x94K\x19h\nK\x16\x8c\x0f%A:Tot / %B:Tot\x94K\x19h\nK\x17\x8c\x17Show percentage of the\n\x94K\x18h\rK\x17\x8c\x15Size / Count column,\n\x94K\x18h\rK\x17\x8c\x16relative to the total\n\x94K\x18h\rK\x17\x8c\x1a(size or count) at either\n\x94K\x18h\rK\x17\x8c\x1athe A or B sample point. \n\x94K\x19h\nK\x1a\x8c\x07Cumul /\x94K\x19h\nK\x17\x8c\x19Show either a cumulative\n\x94K\x18h\nK\x1a\x8c\x00\x94K\x1b\x8c\tA-B / B-A\x94K\x18h\nK\x17\x8c\x18sum of the Size / Count\n\x94K\x18h\rK\x17\x8c\x1acolumn, or the difference\n\x94K\x18h\rK\x17\x8c\rA-B or B-A. \n\x94K\x18h\rK\x14\x8c\x15The cumulative sum is\x94K\x17h&K\x18h\rK\x14\x8c\x19taken by summing from the\x94K\x17h&K\x18h\rK\x14\x8c\x17first table row down to\x94K\x17h&K\x18h\rK\x14\x8c\x0ethe last row. \x94K\x17h&K\x19h\nK\x16hoK\x19h\nK\x17hpK\x18h\rK\x17\x8c\x19previous field, relative\n\x94K\x18h\rK\x17\x8c\x15to either the A or B\n\x94K\x18h\rK\x17\x8c\x08total. \n\x94K\x19h\nK\x16\x8c\x04Kind\x94K\x19h\nK\x17\x8c\x12Shows the kind of\n\x94K\x18h\rK\x17\x8c\x11objects. This is\n\x94K\x18h\rK\x17\x8c\x13currently the only\n\x94K\x18h\rK\x17\x8c\x15alternative for this\n\x94K\x18h\rK\x17\x8c\x17column. The kind shown\n\x94K\x18h\rK\x17\x8c\x19corresponds to the color\n\x94K\x18h\rK\x17\x8c\x13shown in the A / B\n\x94K\x18h\rK\x17\x8c\x1acolumn. A special kind is\n\x94K\x18h\rK\x17\x8c\x19<Other> which summarizes\n\x94K\x18h\rK\x17\x8c\x16the remaining data if\n\x94K\x18h\rK\x17\x8c\x18there were more than 10\n\x94K\x18h\rK\x17\x8c\x17different kinds in the\n\x94K\x18h\rK\x17\x8c\tsample. \n\x94K\x13\x8c\x12Scrollbar submenu\n\x94K\x15h\nK\x16\x8c\x0fAuto / On / Off\x94K\x15h\nK\x17\x8c\x19Choose a scrollbar mode.\n\x94K\x18h\rK\x17\x8c\x1aThe usual setting is Auto\n\x94K\x18h\rK\x17\x8c\x1awhich shows the scrollbar\n\x94K\x18h\rK\x17\x8c\x13only when needed. \n\x94K\x03\x8c\x0cWindow Menu\n\x94K\x0b\x8cqThis menu lists the names of all open windows. Selecting one brings it to the top, deiconifying it if necessary.\n\x94K\x03\x8c\nHelp Menu\n\x94K\x1ch\nK\x06\x8c\x05About\x94K\x1ch\nK\x07\x8c#Version, author, email, copyright.\n\x94K\x1dh\nK\x06\x8c\x04Help\x94K\x1dh\nK\x07\x8c\x17Open this help window.\n\x94K\x00\x8c\x06Panes\n\x94K\x01\x8c\x98There are 3 panes in the main window shown by default. At the top is the Control Panel, at the bottom left the Graph and at the bottom right the Table.\n\x94K\x03\x8c\x13Control Panel Pane\n\x94K\x1e\x8clThis contains controls for the graph and the markers. It also has a quick-exit button and a collect button.\n\x94K\x13\x8c\x13X / Y axis control\n\x94K\x14\x8c\xecThe two frames in the Control Panel having an X or Y button in the top left corner control each axis of the graph. The X, horizontal, axis shows the sample point. The Y axis shows either the size or count, as choosen in the Graph menu.\n\x94K\x1fh\nK\x16\x8c\x0cX / Y Button\x94K\x1fh\nK\x17\x8c\x1cBrings up a menu, currently\n\x94K h\rK\x17\x8c\x18containing some buttons\n\x94K h\rK\x17\x8c\x1athat can also be accessed\n\x94K h\rK\x17\x8c\x18directly in the panel. \n\x94K!h\nK\x16\x8c\x0bGrid button\x94K!h\nK\x17\x8c\x1bSelect if the graph should\n\x94K h\rK\x17\x8c\x12show grid lines. \n\x94K!h\nK\x16\x8c\rRange buttons\x94K!h\nK\x17\x8c\x19Change the range that is\n\x94K h\nK\x16hwK\x1b\x8c\x05- / +\x94K h\nK\x17\x8c\x17shown in the displayed\n\x94K h\rK\x17\x8c\x1aportion of the graph. For\n\x94K h\rK\x17\x8c\x1ceach time + or - is pressed\n\x94K h\rK\x17\x8c\x1athe range will be stepped\n\x94K h\rK\x17\x8c\x1bup or down in the sequence\n\x94K h\rK\x17\x8c\x18(1, 2, 5) and multiples\n\x94K h\rK\x17\x8c\x0bthereoff. \n\x94K!h\nK\x16\x8c\x0bRange field\x94K!h\nK\x17\x8c\x1bThe current range is shown\n\x94K h\rK\x17\x8c\x1ahere, and a new range can\n\x94K h\rK\x17\x8c\x19be entered by writing to\n\x94K h\rK\x17\x8c\x18this field and pressing\n\x94K h\rK\x17\x8c\x18Enter. The format is an\n\x94K h\rK\x17\x8c\x14integer that may be\n\x94K h\rK\x17\x8c\x1afollowed by a multiplier,\n\x94K h\rK\x17\x8c\x1cK, M, G, or T, meaning that\n\x94K h\rK\x17\x8c\x1athe value is multipled by\n\x94K h\rK\x17\x8c\x181000, 1E6, 1E9, or 1E12\n\x94K h\rK\x17\x8c\x1arespectively. The maximum\n\x94K h\rK\x17\x8c\x0erange is 1T. \n\x94K\x13\x8c\x15A / B sample control\n\x94K\x14\x8c\x95Each of the frames showing A or B in the top left corner controls one of the sample markers. The current position is shown in the bottom left corner.\x94K"\x8c\x86(This is currently not an entry field - TODO - but the marker may be moved long distances by directly dragging it in the Graph frame.)\x94K\x14h&K#h\nK\x16h\xaeK#h\nK\x17\x8c\x1cStep the marker one step to\n\x94K$h\rK\x17\x8c\x1dthe left (-) or to the right\n\x94K$h\rK\x17\x8c\x06(+). \n\x94K$h\rK\x14\x8c\x1cThe table will be updated to\x94K\x17h&K$h\rK\x14\x8c\x1bshow new data if it was set\x94K\x17h&K$h\rK\x14\x8c\x1bto show such data that were\x94K\x17h&K$h\rK\x14\x8c\x17dependent on the marker\x94K\x17h&K$h\rK\x14\x8c\x07moved. \x94K\x17h&K$h\rK\x14\x8c\x1bThe graph will show the new\x94K\x17h&K$h\rK\x14\x8c\x17marker position. If the\x94K\x17h&K$h\rK\x14\x8c\x19marker was outside of the\x94K\x17h&K$h\rK\x14\x8c\x18displayed portion of the\x94K\x17h&K$h\rK\x14\x8c\x1cgraph, the graph will scroll\x94K\x17h&K$h\rK\x14\x8c\x15so the marker becomes\x94K\x17h&K$h\rK\x14\x8c\tvisible. \x94K\x17h&K%h\nK\x16\x8c\x0cTrack button\x94K%h\nK\x17\x8c\x1bPress to set the marker to\n\x94K$h\rK\x17\x8c\x1cthe last sample in the file\n\x94K$h\rK\x17\x8c\x1band stay at the end as new\n\x94K$h\rK\x17\x8c\x18samples are added. (New\n\x94K$h\rK\x17\x8c\x19samples are periodically\n\x94K$h\rK\x17\x8c\x19read from the end of the\n\x94K$h\rK\x17\x8c\x1afile when auto-collect is\n\x94K$h\rK\x17\x8c\x19selected via the Collect\n\x94K$h\rK\x17\x8c\nbutton.) \n\x94K$h\rK\x14\x8c\x1bTracking is turned off when\x94K\x17h&K$h\rK\x14\x8c\x16the marker is manually\x94K\x17h&K$h\rK\x14h\xcdK\x17h&K\x13\x8c\x0cExit button\n\x94K\x14\x8cEExits the program, a shortcut for the Exit command in the File menu.\n\x94K\x13\x8c\x0fCollect button\n\x94K\x14\x8cvWhen selected, the browser will collect new samples from the current file, and will continue to do this periodically.\n\x94K"\x8c<Currently it will check the file for new data once a second.\x94K\x14h&K\x03\x8c\x0bGraph Pane\n\x94K\x0bX\x06\x01\x00\x00This pane shows the currently visible portion of the sample file. It can be scrolled via an horizontal scrollbar. The two markers are shown as buttons labeled A and B above the graph and with lines extending down in the graph. Markers can be moved by the mouse.\n\x94K\x07\x8ctHow to move the markers is hopefully quite self evident when tried out but I wrote up some details about it anyway.\n\x94K\x13\x8c\x18Marker movement details\n\x94K&X\x9d\x04\x00\x00Holding down the mouse button and moving the mouse moves the underlying marker. Klicking the mouse button over a marker without moving the mouse, selects the marker. While it is selected any movement of the mouse within the graph will move the marker with it. Klicking again anywhere in the graph will deselect the marker. If the marker can be moved, the cursor will be an arrow indicating the direction it can be moved, left or right or both. If the marker can not be moved in any direction, the cursor will show a circle or disc. The marker can not move outside the available samples. Moving the mouse outside of the graph also restricts the movement of the mouse, even if the mouse button is pressed. This is intentional so that the marker can be moved longer distances than the mouse can move. Moving the mouse to the right of the graph, the marker can only be moved to the right - moving back the mouse will not move the marker back until the mouse enters the graph area again. Similarly for the left side. Above or below the graph, the mouse will not move the marker at all but will show a circle to indicate that the mouse may be \'recirculated\' to move back into the graph.\n\x94K\x03\x8c\x0bTable Pane\n\x94K\x0b\x8c\x7fThis pane shows a table based on the configuration set in the Table menu. The sample number and time stamp show in the header.\n\x94e\x8c\x0btag_configs\x94}\x94(K\x00\x8c\x08spacing1\x94K\n\x86\x94\x8c\x04font\x94\x8c\x05times\x94K\x14\x8c\x04bold\x94\x87\x94\x86\x94\x86\x94K\x01h\xf0h\xf1h\xf2K\x0c\x86\x94\x86\x94\x86\x94K\x02h\xefK\x06\x86\x94h\xf8\x86\x94K\x03h\xefK\t\x86\x94h\xf1h\xf2K\x10\x8c\x04bold\x94\x87\x94\x86\x94\x86\x94K\x04h\xf8\x85\x94K\x06(\x8c\x08lmargin1\x94K$\x86\x94\x8c\x08lmargin2\x94K$\x86\x94h\xfah\xf1h\xf2K\x0c\x8c\x04bold\x94\x87\x94\x86\x94t\x94K\x07(j\x03\x01\x00\x00j\x05\x01\x00\x00h\xfah\xf8t\x94K\x05(\x8c\x04tabs\x94(G@``\x00\x00\x00\x00\x00\x8c\x06center\x94G@m\x80\x00\x00\x00\x00\x00\x8c\x04left\x94t\x94\x86\x94j\x03\x01\x00\x00j\x05\x01\x00\x00h\xfaj\x08\x01\x00\x00t\x94K\x08j\x0f\x01\x00\x00\x85\x94K\tj\x0f\x01\x00\x00h\xfa\x86\x94K\n(j\x03\x01\x00\x00j\x05\x01\x00\x00h\xfah\xf1h\xf2K\x0c\x8c\x06italic\x94\x87\x94\x86\x94t\x94K\x0bj\x03\x01\x00\x00j\x05\x01\x00\x00h\xf8\x87\x94K\x0c(j\x0b\x01\x00\x00(G@_\x80\x00\x00\x00\x00\x00j\x0c\x01\x00\x00G@l@\x00\x00\x00\x00\x00j\r\x01\x00\x00t\x94\x86\x94j\x03\x01\x00\x00j\x05\x01\x00\x00h\xfaj\x08\x01\x00\x00t\x94K\rj\x19\x01\x00\x00\x85\x94K\x0ej\x19\x01\x00\x00h\xfa\x86\x94K\x0f(j\x0b\x01\x00\x00(G@X\x00\x00\x00\x00\x00\x00j\x0c\x01\x00\x00G@d\xc0\x00\x00\x00\x00\x00j\r\x01\x00\x00t\x94\x86\x94j\x03\x01\x00\x00j\x05\x01\x00\x00h\xfaj\x08\x01\x00\x00t\x94K\x10j\x1e\x01\x00\x00\x85\x94K\x11j\x1e\x01\x00\x00h\xfa\x86\x94K\x12j\x03\x01\x00\x00j\x05\x01\x00\x00h\xf1h\xf2K\n\x86\x94\x86\x94\x87\x94K\x13(j\x03\x01\x00\x00j\x05\x01\x00\x00h\xefK\x08\x86\x94j\x08\x01\x00\x00t\x94K\x16(j\x02\x01\x00\x00KH\x86\x94j\x04\x01\x00\x00KH\x86\x94h\xfaj\x08\x01\x00\x00t\x94K\x17(j\'\x01\x00\x00j(\x01\x00\x00h\xfah\xf8t\x94K\x15(j\x0b\x01\x00\x00(G@b`\x00\x00\x00\x00\x00j\x0c\x01\x00\x00G@m\x00\x00\x00\x00\x00\x00j\r\x01\x00\x00t\x94\x86\x94j\'\x01\x00\x00j(\x01\x00\x00h\xfaj\x08\x01\x00\x00t\x94K\x18j,\x01\x00\x00\x85\x94K\x14j\'\x01\x00\x00j(\x01\x00\x00h\xf8\x87\x94K\x19j,\x01\x00\x00h\xfa\x86\x94K\x1aj)\x01\x00\x00K\x1bj\'\x01\x00\x00j(\x01\x00\x00j\x08\x01\x00\x00\x87\x94K\x1c(j\x0b\x01\x00\x00(G@N\x80\x00\x00\x00\x00\x00j\x0c\x01\x00\x00G@X\x00\x00\x00\x00\x00\x00j\r\x01\x00\x00t\x94\x86\x94j\x03\x01\x00\x00j\x05\x01\x00\x00h\xfaj\x08\x01\x00\x00t\x94K\x1dj3\x01\x00\x00h\xfa\x86\x94K\x1eh\xfch\xf8\x86\x94K\x1f(j\x0b\x01\x00\x00(G@a \x00\x00\x00\x00\x00j\x0c\x01\x00\x00G@j\x80\x00\x00\x00\x00\x00j\r\x01\x00\x00t\x94\x86\x94j\'\x01\x00\x00j(\x01\x00\x00h\xfaj\x08\x01\x00\x00t\x94K j8\x01\x00\x00\x85\x94K!j8\x01\x00\x00h\xfa\x86\x94K"j\'\x01\x00\x00j(\x01\x00\x00j#\x01\x00\x00\x87\x94K#(j\x0b\x01\x00\x00(G@`\x80\x00\x00\x00\x00\x00j\x0c\x01\x00\x00G@i@\x00\x00\x00\x00\x00j\r\x01\x00\x00t\x94\x86\x94j\'\x01\x00\x00j(\x01\x00\x00h\xfaj\x08\x01\x00\x00t\x94K$j>\x01\x00\x00\x85\x94K%j>\x01\x00\x00h\xfa\x86\x94K&(j\x03\x01\x00\x00j\x05\x01\x00\x00j%\x01\x00\x00h\xf8t\x94u\x8c\n_gsl_title\x94\x8c\x1eHelp for Heapy Profile Browser\x94ub.'
diff --git a/setup.py b/setup.py
index 521432c..902c972 100644
--- a/setup.py
+++ b/setup.py
@@ -58,7 +58,7 @@ def doit():
               "guppy.sets",
           ],
           ext_modules=[setsc, heapyc],
-          python_requires='>=3.6',
+          python_requires='>=3.7',
           classifiers=[
               "Programming Language :: Python :: 3",
               "Programming Language :: Python :: Implementation :: CPython",
diff --git a/specs/index.gsl b/specs/index.gsl
index a21a641..7c7297e 100644
--- a/specs/index.gsl
+++ b/specs/index.gsl
@@ -182,7 +182,7 @@ points in time.
 ...div
 ....ul
 
-.....li: Can be used with an unmodified C Python, back to version 3.6
+.....li: Can be used with an unmodified C Python, back to version 3.7
 AFAIK. Does not depend on any external unix-specific or other
 utilities.
 
diff --git a/src/heapy/classifier.c b/src/heapy/classifier.c
index 6419fb2..fba664c 100644
--- a/src/heapy/classifier.c
+++ b/src/heapy/classifier.c
@@ -39,10 +39,10 @@ static void
 cli_dealloc(NyObjectClassifierObject *op)
 {
     PyObject_GC_UnTrack(op);
-    Py_TRASHCAN_SAFE_BEGIN(op)
+    Ny_TRASHCAN_BEGIN(op, cli_dealloc)
     Py_XDECREF(op->self);
     PyObject_GC_Del(op);
-    Py_TRASHCAN_SAFE_END(op)
+    Ny_TRASHCAN_END(op)
 }
 
 static int
diff --git a/src/heapy/hv.c b/src/heapy/hv.c
index 169b3b6..fda50c1 100644
--- a/src/heapy/hv.c
+++ b/src/heapy/hv.c
@@ -522,6 +522,15 @@ xt_size(ExtraType *xt, PyObject *obj)
 static int
 xt_traverse(ExtraType *xt, PyObject *obj, visitproc visit, void *arg)
 {
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    if (Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MANAGED_DICT) {
+        // FIXME: There's no way to distinguish between managed dict entries
+        // and other references. To keep our results stable we have to
+        // materialize this managed dict, which allocates a lot of memory
+        // and will add additional overhead.
+        _PyObject_GetDictPtr(obj);
+    }
+#endif
     if (xt->xt_trav_code == XT_NO)
         return 0;
     else if (xt->xt_trav_code == XT_TP)
@@ -740,10 +749,10 @@ static void
 hv_dealloc(PyObject *v)
 {
     PyObject_GC_UnTrack(v);
-    Py_TRASHCAN_SAFE_BEGIN(v)
+    Ny_TRASHCAN_BEGIN(v, hv_dealloc)
     hv_gc_clear((NyHeapViewObject *)v);
     Py_TYPE(v)->tp_free(v);
-    Py_TRASHCAN_SAFE_END(v)
+    Ny_TRASHCAN_END(v)
 }
 
 PyDoc_STRVAR(hv_delete_extra_type_doc,
diff --git a/src/heapy/hv_cli_prod.c b/src/heapy/hv_cli_prod.c
index 24349d0..56bee1d 100644
--- a/src/heapy/hv_cli_prod.c
+++ b/src/heapy/hv_cli_prod.c
@@ -12,6 +12,14 @@ PyDoc_STRVAR(hv_cli_prod_doc,
 "                memoize the classification sets.\n"
 );
 
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+# define Py_BUILD_CORE
+#  undef _PyObject_LookupSpecial
+/* _PyType_PreHeaderSize */
+#  include <internal/pycore_object.h>
+# undef Py_BUILD_CORE
+#endif
+
 // The sizeof of PyGC_Head is not to be trusted upon even across Python minor
 // releases. Eg: python/cpython@8766cb7
 static Py_ssize_t sizeof_PyGC_Head;
@@ -100,6 +108,15 @@ hv_cli_prod_classify(ProdObject *self, PyObject *obj)
         ptr = (Py_uintptr_t)obj;
     }
 
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    // https://github.com/python/cpython/issues/101430
+    ptr -= _PyType_PreHeaderSize(Py_TYPE(obj));
+    // _PyType_PreHeaderSize would add an extra compile-time sizeof(PyGC_Head),
+    // which may be different from the true value in sizeof_PyGC_Head
+    if (PyType_IS_GC(Py_TYPE(obj)))
+        ptr += sizeof(PyGC_Head);
+#endif
+
     tb = _PyTraceMalloc_GetTraceback(0, (Py_uintptr_t)ptr);
 
     if (!tb)
diff --git a/src/heapy/hv_cli_rel.c b/src/heapy/hv_cli_rel.c
index 052a771..5b7725f 100644
--- a/src/heapy/hv_cli_rel.c
+++ b/src/heapy/hv_cli_rel.c
@@ -26,10 +26,10 @@ static void
 rel_dealloc(NyRelationObject *op)
 {
     PyObject_GC_UnTrack(op);
-    Py_TRASHCAN_SAFE_BEGIN(op)
+    Ny_TRASHCAN_BEGIN(op, rel_dealloc)
     Py_XDECREF(op->relator);
     Py_TYPE(op)->tp_free(op);
-    Py_TRASHCAN_SAFE_END(op)
+    Ny_TRASHCAN_END(op)
 }
 
 PyObject *
diff --git a/src/heapy/interpreter.c b/src/heapy/interpreter.c
index 81928a4..eb2e862 100644
--- a/src/heapy/interpreter.c
+++ b/src/heapy/interpreter.c
@@ -38,61 +38,10 @@ static char hp_set_async_exc_doc[] =
 /* _PyMem_SetDefaultAllocator */
 #  include <internal/pycore_pymem.h>
 # undef Py_BUILD_CORE
-#elif PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
+#else
 PyAPI_FUNC(int) _PyMem_SetDefaultAllocator(
     PyMemAllocatorDomain domain,
     PyMemAllocatorEx *old_alloc);
-#else
-// source: cpython: Objects/obmalloc.c
-static void *
-_PyMem_RawMalloc(void *ctx, size_t size)
-{
-    if (size == 0)
-        size = 1;
-    return malloc(size);
-}
-
-static void *
-_PyMem_RawCalloc(void *ctx, size_t nelem, size_t elsize)
-{
-    if (nelem == 0 || elsize == 0) {
-        nelem = 1;
-        elsize = 1;
-    }
-    return calloc(nelem, elsize);
-}
-
-static void *
-_PyMem_RawRealloc(void *ctx, void *ptr, size_t size)
-{
-    if (size == 0)
-        size = 1;
-    return realloc(ptr, size);
-}
-
-static void
-_PyMem_RawFree(void *ctx, void *ptr)
-{
-    free(ptr);
-}
-
-static int _PyMem_SetDefaultAllocator(
-    PyMemAllocatorDomain domain,
-    PyMemAllocatorEx *old_alloc)
-{
-    assert(domain == PYMEM_DOMAIN_RAW);
-    PyMem_GetAllocator(domain, old_alloc);
-
-    PyMemAllocatorEx alloc = {
-        .malloc  = _PyMem_RawMalloc,
-        .calloc  = _PyMem_RawCalloc,
-        .realloc = _PyMem_RawRealloc,
-        .free    = _PyMem_RawFree,
-        .ctx     = NULL
-    };
-    PyMem_SetAllocator(domain, &alloc);
-    return 0;
-}
 #endif
 
 struct bootstate {
diff --git a/src/heapy/nodegraph.c b/src/heapy/nodegraph.c
index a21113e..2fd9c83 100644
--- a/src/heapy/nodegraph.c
+++ b/src/heapy/nodegraph.c
@@ -111,8 +111,8 @@ ng_dealloc(PyObject *v)
 {
     NyNodeGraphObject *ng = (void *)v;
     Py_ssize_t i;
-    Py_TRASHCAN_SAFE_BEGIN(v)
     PyObject_GC_UnTrack(v);
+    Ny_TRASHCAN_BEGIN(v, ng_dealloc)
     ng_gc_clear(ng);
     for (i = 0; i < ng->used_size; i++) {
         Py_DECREF(ng->edges[i].src);
@@ -120,8 +120,7 @@ ng_dealloc(PyObject *v)
     }
     PyMem_FREE(ng->edges);
     Py_TYPE(ng)->tp_free(v);
-    Py_TRASHCAN_SAFE_END(v)
-
+    Ny_TRASHCAN_END(v)
 }
 
 static int
diff --git a/src/heapy/rootstate.c b/src/heapy/rootstate.c
index a513bbf..252bc51 100644
--- a/src/heapy/rootstate.c
+++ b/src/heapy/rootstate.c
@@ -154,15 +154,13 @@ static struct PyMemberDef is_members[] = {
     MEMBER(builtins_copy),
     MEMBER(import_func),
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
-# ifdef HAVE_FORK
+#ifdef HAVE_FORK
     MEMBER(before_forkers),
     MEMBER(after_forkers_parent),
     MEMBER(after_forkers_child),
-# endif
-# if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
     MEMBER(pyexitmodule),
-# endif
 #endif
 
 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8
@@ -177,7 +175,10 @@ static struct PyMemberDef is_members[] = {
 #define RENAMEMEMBER(name, newname) {#newname, T_OBJECT, offsetof(PyThreadState, name)}
 
 static struct PyMemberDef ts_members[] = {
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 11
     MEMBER(frame),
+#endif
+
     MEMBER(c_profileobj),
     MEMBER(c_traceobj),
 
@@ -185,14 +186,12 @@ static struct PyMemberDef ts_members[] = {
     MEMBER(curexc_value),
     MEMBER(curexc_traceback),
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    RENAMEMEMBER(exc_state.exc_value, exc_value),
+#else
     RENAMEMEMBER(exc_state.exc_type, exc_type),
     RENAMEMEMBER(exc_state.exc_value, exc_value),
     RENAMEMEMBER(exc_state.exc_traceback, exc_traceback),
-#else
-    MEMBER(exc_type),
-    MEMBER(exc_value),
-    MEMBER(exc_traceback),
 #endif
 
     MEMBER(dict),
@@ -206,9 +205,7 @@ static struct PyMemberDef ts_members[] = {
     MEMBER(async_gen_firstiter),
     MEMBER(async_gen_finalizer),
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
     MEMBER(context),
-#endif
     {0} /* Sentinel */
 };
 
@@ -288,32 +285,47 @@ rootstate_relate(NyHeapRelate *r)
         ISATTR(builtins_copy);
         ISATTR(import_func);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
-# ifdef HAVE_FORK
+#ifdef HAVE_FORK
         ISATTR(before_forkers);
         ISATTR(after_forkers_parent);
         ISATTR(after_forkers_child);
-# endif
-# if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
         ISATTR(pyexitmodule);
-# endif
 #endif
 
 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8
         ISATTR(audit_hooks);
 #endif
 
-        for (ts = is->tstate_head; ts; ts = ts->next) {
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+        ts = is->threads.head;
+#else
+        ts = is->tstate_head;
+#endif
+        for (; ts; ts = ts->next) {
             if ((ts == bts && r->tgt == hv->limitframe) ||
                     (!hv->limitframe && isframe)) {
                 int frameno = -1;
                 int numframes = 0;
                 PyFrameObject *frame;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+                for (frame = PyThreadState_GetFrame(ts); frame;) {
+                    PyFrameObject *next_frame = PyFrame_GetBack(frame);
+                    numframes++;
+                    if ((PyObject *)frame == r->tgt)
+                        frameno = numframes;
+
+                    Py_DECREF(frame);
+                    frame = next_frame;
+                }
+#else
                 for (frame = (PyFrameObject *)ts->frame; frame; frame = frame->f_back) {
                     numframes++;
-                    if (r->tgt == (PyObject *)frame)
+                    if ((PyObject *)frame == r->tgt)
                         frameno = numframes;
                 }
+#endif
                 if (frameno != -1) {
                     frameno = numframes - frameno;
                     if (r->visit(NYHR_ATTRIBUTE, PyUnicode_FromFormat("i%d_t%lu_f%d", isno, THREAD_ID(ts), frameno), r))
@@ -327,14 +339,12 @@ rootstate_relate(NyHeapRelate *r)
             TSATTR(curexc_value);
             TSATTR(curexc_traceback);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+            RENAMETSATTR(exc_state.exc_value, exc_value);
+#else
             RENAMETSATTR(exc_state.exc_type, exc_type);
             RENAMETSATTR(exc_state.exc_value, exc_value);
             RENAMETSATTR(exc_state.exc_traceback, exc_traceback);
-#else
-            TSATTR(exc_type);
-            TSATTR(exc_value);
-            TSATTR(exc_traceback);
 #endif
 
             TSATTR(dict);
@@ -347,9 +357,7 @@ rootstate_relate(NyHeapRelate *r)
             TSATTR(async_gen_firstiter);
             TSATTR(async_gen_finalizer);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
             TSATTR(context);
-#endif
         }
     }
     return 0;
@@ -391,26 +399,35 @@ rootstate_traverse(NyHeapTraverse *ta)
         Py_VISIT(is->builtins_copy);
         Py_VISIT(is->import_func);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
-# ifdef HAVE_FORK
+#ifdef HAVE_FORK
         Py_VISIT(is->before_forkers);
         Py_VISIT(is->after_forkers_parent);
         Py_VISIT(is->after_forkers_child);
-# endif
-# if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
         Py_VISIT(is->pyexitmodule);
-# endif
 #endif
 
 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8
         Py_VISIT(is->audit_hooks);
 #endif
 
-        for (ts = is->tstate_head; ts; ts = ts->next) {
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+        ts = is->threads.head;
+#else
+        ts = is->tstate_head;
+#endif
+        for (; ts; ts = ts->next) {
             if (ts == bts && hv->limitframe) {
                 Py_VISIT(hv->limitframe);
             } else if (!hv->limitframe) {
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+                PyFrameObject *frame = PyThreadState_GetFrame(ts);
+                Py_VISIT(frame);
+                Py_XDECREF(frame);
+#else
                 Py_VISIT(ts->frame);
+#endif
             }
             Py_VISIT(ts->c_profileobj);
             Py_VISIT(ts->c_traceobj);
@@ -419,14 +436,12 @@ rootstate_traverse(NyHeapTraverse *ta)
             Py_VISIT(ts->curexc_value);
             Py_VISIT(ts->curexc_traceback);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+            Py_VISIT(ts->exc_state.exc_value);
+#else
             Py_VISIT(ts->exc_state.exc_type);
             Py_VISIT(ts->exc_state.exc_value);
             Py_VISIT(ts->exc_state.exc_traceback);
-#else
-            Py_VISIT(ts->exc_type);
-            Py_VISIT(ts->exc_value);
-            Py_VISIT(ts->exc_traceback);
 #endif
 
             Py_VISIT(ts->dict);
@@ -439,9 +454,7 @@ rootstate_traverse(NyHeapTraverse *ta)
             Py_VISIT(ts->async_gen_firstiter);
             Py_VISIT(ts->async_gen_finalizer);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
             Py_VISIT(ts->context);
-#endif
         }
     }
     return 0;
@@ -468,6 +481,7 @@ rootstate_getattr(PyObject *obj, PyObject *name)
 {
     const char *s = PyUnicode_AsUTF8(name);
     PyInterpreterState *is;
+    PyThreadState *ts;
     int n = 0;
     int ino;
     unsigned long tno;
@@ -492,24 +506,51 @@ rootstate_getattr(PyObject *obj, PyObject *name)
             if (isno == ino) {
                 if (sscanf(s, "t%lu_%n", &tno, &n) == 1) {
                     s += n;
-                    PyThreadState *ts;
-                    for (ts = is->tstate_head; ts; ts = ts->next) {
+
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+                    ts = is->threads.head;
+#else
+                    ts = is->tstate_head;
+#endif
+                    for (; ts; ts = ts->next) {
                         if (THREAD_ID(ts) == tno) {
                             int frameno = 0;
                             if (sscanf(s, "f%d%n", &frameno, &n) == 1 && s[n] == '\0') {
-                                PyFrameObject *frame;
                                 int numframes = 0;
+                                PyFrameObject *frame;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+                                PyFrameObject *current_frame = PyThreadState_GetFrame(ts);
+                                for (frame = (PyFrameObject *)Py_XNewRef(current_frame); frame;) {
+                                    PyFrameObject *next_frame = PyFrame_GetBack(frame);
+                                    numframes++;
+                                    Py_DECREF(frame);
+                                    frame = next_frame;
+                                }
+                                for (frame = (PyFrameObject *)Py_XNewRef(current_frame); frame;) {
+                                    PyFrameObject *next_frame = PyFrame_GetBack(frame);
+                                    numframes--;
+                                    if (numframes == frameno) {
+                                        Py_DECREF(current_frame);
+                                        Py_DECREF(name);
+                                        return (PyObject *)frame;
+                                    }
+                                    Py_DECREF(frame);
+                                    frame = next_frame;
+                                }
+                                Py_DECREF(current_frame);
+#else
                                 for (frame = ts->frame; frame; frame = frame->f_back) {
-                                    numframes ++;
+                                    numframes++;
                                 }
                                 for (frame = ts->frame; frame; frame = frame->f_back) {
-                                    numframes --;
+                                    numframes--;
                                     if (numframes == frameno) {
                                         Py_INCREF(frame);
                                         Py_DECREF(name);
                                         return (PyObject *)frame;
                                     }
                                 }
+#endif
                                 PyErr_Format(PyExc_AttributeError,
                                              "thread state has no frame numbered %d from bottom",
                                              frameno);
@@ -559,8 +600,13 @@ rootstate_getattr(PyObject *obj, PyObject *name)
                 continue;
 #endif
             int isno = numis - countis - 1;
-            PyThreadState *ts;
-            for (ts = is->tstate_head; ts; ts = ts->next) {
+
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+            ts = is->threads.head;
+#else
+            ts = is->tstate_head;
+#endif
+            for (; ts; ts = ts->next) {
                 if (THREAD_ID(ts) == tno) {
                     PyObject *fullname = PyUnicode_FromFormat("i%d_%U", isno, name);
                     if (!fullname) {
@@ -636,37 +682,51 @@ rootstate_dir(PyObject *self, PyObject *args)
         ISATTR_DIR(builtins_copy);
         ISATTR_DIR(import_func);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
-# ifdef HAVE_FORK
+#ifdef HAVE_FORK
         ISATTR_DIR(before_forkers);
         ISATTR_DIR(after_forkers_parent);
         ISATTR_DIR(after_forkers_child);
-# endif
-# if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 10
         ISATTR_DIR(pyexitmodule);
-# endif
 #endif
 
 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8
         ISATTR_DIR(audit_hooks);
 #endif
 
-        for (ts = is->tstate_head; ts; ts = ts->next) {
+
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+        ts = is->threads.head;
+#else
+        ts = is->tstate_head;
+#endif
+        for (; ts; ts = ts->next) {
             int numframes = 0;
             PyFrameObject *frame;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+            for (frame = PyThreadState_GetFrame(ts); frame;) {
+                PyFrameObject *next_frame = PyFrame_GetBack(frame);
+                numframes++;
+                Py_DECREF(frame);
+                frame = next_frame;
+            }
+#else
             for (frame = (PyFrameObject *)ts->frame; frame; frame = frame->f_back) {
                 numframes++;
             }
+#endif
             int frameno;
             for (frameno = 0; frameno < numframes; frameno++) {
                 attr = PyUnicode_FromFormat("i%d_t%lu_f%d", isno, THREAD_ID(ts), frameno);
-                if (attr) {
-                    if (PyList_Append(list, attr)) {
-                        Py_DECREF(attr);
-                        goto Err;
-                    }
+                if (!attr)
+                    goto Err;
+
+                if (PyList_Append(list, attr)) {
                     Py_DECREF(attr);
+                    goto Err;
                 }
+                Py_DECREF(attr);
             }
             TSATTR_DIR(c_profileobj);
             TSATTR_DIR(c_traceobj);
@@ -689,9 +749,7 @@ rootstate_dir(PyObject *self, PyObject *args)
             TSATTR_DIR(async_gen_firstiter);
             TSATTR_DIR(async_gen_finalizer);
 
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
             TSATTR_DIR(context);
-#endif
         }
     }
 
diff --git a/src/heapy/stdtypes.c b/src/heapy/stdtypes.c
index 0b623fa..48b61ba 100644
--- a/src/heapy/stdtypes.c
+++ b/src/heapy/stdtypes.c
@@ -1,6 +1,15 @@
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
 
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+# define Py_BUILD_CORE
+/* PyFrameObject */
+#  include <internal/pycore_frame.h>
+/* _PyLocals_GetKind */
+#  include <internal/pycore_code.h>
+# undef Py_BUILD_CORE
+#endif
+
 #include "structmember.h"
 #include "compile.h"
 #include "frameobject.h"
@@ -14,17 +23,13 @@
 #define ALIGN_MASK (ALIGNMENT - 1)
 #define ALIGN(z)   ((z + ALIGN_MASK) & ~ALIGN_MASK)
 
-#define ATTR(name) if ((PyObject *)v->name == r->tgt &&        \
-    (r->visit(NYHR_ATTRIBUTE, PyUnicode_FromString(#name), r))) \
+#define GATTR(obj, name, rel) if ((PyObject *)(obj) == r->tgt &&        \
+    (r->visit(rel, PyUnicode_FromString(#name), r))) \
         return 1;
 
-#define RENAMEATTR(name, newname) if ((PyObject *)v->name == r->tgt && \
-    (r->visit(NYHR_ATTRIBUTE, PyUnicode_FromString(#newname), r)))      \
-        return 1;
-
-#define INTERATTR(name) if ((PyObject *)v->name == r->tgt &&   \
-    (r->visit(NYHR_INTERATTR, PyUnicode_FromString(#name), r))) \
-        return 1;
+#define ATTR(name) GATTR(v->name, name, NYHR_ATTRIBUTE)
+#define RENAMEATTR(name, newname) GATTR(v->name, newname, NYHR_ATTRIBUTE)
+#define INTERATTR(name) GATTR(v->name, newname, NYHR_INTERATTR)
 
 extern PyObject *_hiding_tag__name;
 
@@ -174,6 +179,7 @@ module_relate(NyHeapRelate *r)
     return dict_relate_kv(r, dct, NYHR_HASATTR, NYHR_ATTRIBUTE);
 }
 
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 11
 static int
 frame_locals(NyHeapRelate *r, PyObject *map, Py_ssize_t start, Py_ssize_t n, int deref)
 {
@@ -195,28 +201,66 @@ frame_locals(NyHeapRelate *r, PyObject *map, Py_ssize_t start, Py_ssize_t n, int
     }
     return 0;
 }
+#endif
 
 static int
 frame_relate(NyHeapRelate *r)
 {
     PyFrameObject *v = (void *)r->src;
-    PyCodeObject *co = v->f_code;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    _PyInterpreterFrame *iv = v->f_frame;
+#else
+    PyFrameObject *iv = v;
+#endif
+    PyCodeObject *co = iv->f_code;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 11
     Py_ssize_t ncells = PyTuple_GET_SIZE(co->co_cellvars);
-    Py_ssize_t nlocals = co->co_nlocals;
+    Py_ssize_t nlocals = co->co_nlocals;;
     Py_ssize_t nfreevars = PyTuple_GET_SIZE(co->co_freevars);
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    // Py 3.11 only holds f_back when FRAME_OWNED_BY_FRAME_OBJECT
+    PyFrameObject *next_frame = PyFrame_GetBack(v);
+    if ((PyObject *)next_frame == r->tgt && r->visit(
+            NYHR_ATTRIBUTE, PyUnicode_FromString("f_back"), r)) {
+        Py_XDECREF(next_frame);
+        return 1;
+    }
+    Py_XDECREF(next_frame);
+#endif
     ATTR(f_back)
-    ATTR(f_code)
-    ATTR(f_builtins)
-    ATTR(f_globals)
-    ATTR(f_locals)
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    GATTR(iv->f_func, f_func, NYHR_INTERATTR)
+#endif
+    GATTR(iv->f_code, f_code, NYHR_ATTRIBUTE)
+    GATTR(iv->f_builtins, f_builtins, NYHR_ATTRIBUTE)
+    GATTR(iv->f_globals, f_globals, NYHR_ATTRIBUTE)
+    GATTR(iv->f_locals, f_locals, NYHR_ATTRIBUTE)
     ATTR(f_trace)
-    /*
-    ATTR(f_exc_type)
-    ATTR(f_exc_value)
-    ATTR(f_exc_traceback)
-    */
 
     /* locals */
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    Py_ssize_t i;
+    for (i = 0; i < co->co_nlocalsplus; i++) {
+        _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
+        PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
+
+        if (iv->localsplus[i] == r->tgt) {
+            Py_INCREF(name);
+            if (r->visit(NYHR_LOCAL_VAR, name, r))
+                return 1;
+        }
+
+        if (!(kind & CO_FAST_CELL) && !(kind & CO_FAST_FREE))
+            continue;
+
+        if (PyCell_GET(iv->localsplus[i]) == r->tgt) {
+            Py_INCREF(name);
+            if (r->visit(NYHR_CELL, name, r))
+                return 1;
+        }
+    }
+#else
     if (
         frame_locals(r, co->co_varnames, 0, nlocals, 0) ||
         frame_locals(r, co->co_cellvars, nlocals, ncells, 0) ||
@@ -224,9 +268,20 @@ frame_relate(NyHeapRelate *r)
         frame_locals(r, co->co_freevars, nlocals + ncells, nfreevars, 0) ||
         frame_locals(r, co->co_freevars, nlocals + ncells, nfreevars, 1))
         return 1;
+#endif
 
     /* stack */
-#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 10
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    PyObject **p;
+    PyObject **s = iv->localsplus + co->co_nlocalsplus;
+    PyObject **e = iv->localsplus + iv->stacktop;
+    for (p = s; p < e; p++) {
+        if (*p == r->tgt) {
+            if (r->visit(NYHR_STACK, PyLong_FromSsize_t(p-s), r))
+                return 1;
+        }
+    }
+#elif PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 10
     PyObject **p;
     PyObject **l = v->f_valuestack + v->f_stackdepth;
     for (p = v->f_valuestack; p < l; p++) {
@@ -252,10 +307,29 @@ frame_relate(NyHeapRelate *r)
 static int
 frame_traverse(NyHeapTraverse *ta) {
     PyFrameObject *v = (void *)ta->obj;
-    PyCodeObject *co = v->f_code;
+    visitproc visit = ta->visit;
+    void *arg = ta->arg;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    _PyInterpreterFrame *iv = v->f_frame;
+#else
+    PyFrameObject *iv = v;
+#endif
+    PyCodeObject *co = iv->f_code;
+    int i;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    for (i = 0; i < co->co_nlocalsplus; i++) {
+        _PyLocals_Kind kind = _PyLocals_GetKind(co->co_localspluskinds, i);
+        PyObject *name = PyTuple_GET_ITEM(co->co_localsplusnames, i);
+        if (kind & CO_FAST_LOCAL && strcmp(PyUnicode_AsUTF8(name), "_hiding_tag_") == 0) {
+            if (iv->localsplus[i] == ta->_hiding_tag_)
+                return 0;
+            else
+                break;
+        }
+    }
+#else
     int nlocals = co->co_nlocals;
     if (PyTuple_Check(co->co_varnames)) {
-        int i;
         for (i = 0; i < nlocals; i++) {
             PyObject *name = PyTuple_GET_ITEM(co->co_varnames, i);
             if (strcmp(PyUnicode_AsUTF8(name), "_hiding_tag_") == 0) {
@@ -266,7 +340,30 @@ frame_traverse(NyHeapTraverse *ta) {
             }
         }
     }
-    return Py_TYPE(v)->tp_traverse(ta->obj, ta->visit, ta->arg);
+#endif
+
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    /* _PyFrame_Traverse is not exposed and CPython's frame_traverse only
+      calls it when FRAME_OWNED_BY_FRAME_OBJECT :( */
+    PyFrameObject *next_frame = PyFrame_GetBack(v);
+    Py_VISIT(next_frame);
+    Py_XDECREF(next_frame);
+
+    Py_VISIT(v->f_trace);
+    Py_VISIT(iv->f_func);
+    Py_VISIT(iv->f_code);
+    Py_VISIT(iv->f_builtins);
+    Py_VISIT(iv->f_globals);
+    Py_VISIT(iv->f_locals);
+
+    /* locals */
+    for (i = 0; i < co->co_nlocalsplus; i++)
+        Py_VISIT(iv->localsplus[i]);
+
+    return 0;
+#else
+    return Py_TYPE(v)->tp_traverse(ta->obj, visit, arg);
+#endif
 }
 
 
@@ -303,19 +400,71 @@ code_traverse(NyHeapTraverse *ta) {
     PyCodeObject *co = (void *)ta->obj;
     visitproc visit = ta->visit;
     void *arg = ta->arg;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    Py_VISIT(co->_co_code);
+#else
     Py_VISIT(co->co_code);
+#endif
     Py_VISIT(co->co_consts);
     Py_VISIT(co->co_names);
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    Py_VISIT(co->co_exceptiontable);
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    Py_VISIT(co->co_localsplusnames);
+    Py_VISIT(co->co_localspluskinds);
+#else
     Py_VISIT(co->co_varnames);
     Py_VISIT(co->co_freevars);
     Py_VISIT(co->co_cellvars);
+#endif
     Py_VISIT(co->co_filename);
     Py_VISIT(co->co_name);
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    Py_VISIT(co->co_qualname);
+#endif
 #if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 10
     Py_VISIT(co->co_linetable);
 #else
     Py_VISIT(co->co_lnotab);
 #endif
+    Py_VISIT(co->co_weakreflist);
+    return 0;
+}
+
+static int
+code_relate(NyHeapRelate *r)
+{
+    PyCodeObject *v = (void *)r->src;
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    RENAMEATTR(_co_code, co_code);
+#else
+    ATTR(co_code);
+#endif
+    ATTR(co_consts);
+    ATTR(co_names);
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    ATTR(co_exceptiontable);
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    INTERATTR(co_localsplusnames);
+    INTERATTR(co_localspluskinds);
+#else
+    ATTR(co_varnames);
+    ATTR(co_freevars);
+    ATTR(co_cellvars);
+#endif
+    ATTR(co_filename);
+    ATTR(co_name);
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 11
+    ATTR(co_qualname);
+#endif
+#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 10
+    ATTR(co_linetable);
+#else
+    ATTR(co_lnotab);
+#endif
+    ATTR(co_weakreflist);
     return 0;
 }
 
@@ -442,7 +591,7 @@ NyHeapDef NyStdTypes_HeapDef[] = {
         0,             /* type */
         0,             /* size */
         code_traverse, /* traverse */
-        0              /* relate */
+        code_relate    /* relate */
     }, {
         0,             /* flags */
         0,             /* type */
diff --git a/src/include/guppy.h b/src/include/guppy.h
index 9aeb9e2..afca472 100644
--- a/src/include/guppy.h
+++ b/src/include/guppy.h
@@ -7,4 +7,12 @@
     if (PyType_Ready(&t) < 0) return -1; \
 }
 
+#if PY_VERSION_HEX >= 0x03080000
+#  define Ny_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN(op, dealloc)
+#  define Ny_TRASHCAN_END(op) Py_TRASHCAN_END
+#else
+#  define Ny_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_SAFE_BEGIN(op)
+#  define Ny_TRASHCAN_END(op) Py_TRASHCAN_SAFE_END(op)
+#endif
+
 #endif /* GUPPY_H_INCLUDED */
diff --git a/src/sets/bitset.c b/src/sets/bitset.c
index 5409313..c01fb3f 100644
--- a/src/sets/bitset.c
+++ b/src/sets/bitset.c
@@ -4,7 +4,7 @@
 #include <Python.h>
 
 #include "structmember.h"
-#include "longintrepr.h"
+// #include "longintrepr.h"
 
 #include "../include/guppy.h"
 #include "../include/pythoncapi_compat.h"
diff --git a/src/sets/immnodeset.c b/src/sets/immnodeset.c
index 22c8453..d1f8b58 100644
--- a/src/sets/immnodeset.c
+++ b/src/sets/immnodeset.c
@@ -30,10 +30,10 @@ static void
 immnsiter_dealloc(NyImmNodeSetIterObject *it)
 {
     PyObject_GC_UnTrack(it);
-    Py_TRASHCAN_SAFE_BEGIN(it)
-        Py_XDECREF(it->nodeset);
-        PyObject_GC_Del(it);
-    Py_TRASHCAN_SAFE_END(it)
+    Ny_TRASHCAN_BEGIN(it, immnsiter_dealloc)
+    Py_XDECREF(it->nodeset);
+    PyObject_GC_Del(it);
+    Ny_TRASHCAN_END(it)
 }
 
 static PyObject *
@@ -222,10 +222,10 @@ static void
 immnodeset_dealloc(NyNodeSetObject *v)
 {
     PyObject_GC_UnTrack(v);
-    Py_TRASHCAN_SAFE_BEGIN(v)
+    Ny_TRASHCAN_BEGIN(v, immnodeset_dealloc)
     immnodeset_gc_clear(v);
     Py_TYPE(v)->tp_free((PyObject *)v);
-    Py_TRASHCAN_SAFE_END(v)
+    Ny_TRASHCAN_END(v)
 }
 
 
diff --git a/src/sets/nodeset.c b/src/sets/nodeset.c
index 60f2607..4ae121e 100644
--- a/src/sets/nodeset.c
+++ b/src/sets/nodeset.c
@@ -390,10 +390,10 @@ static void
 mutnodeset_dealloc(NyNodeSetObject *v)
 {
     PyObject_GC_UnTrack(v);
-    Py_TRASHCAN_SAFE_BEGIN(v)
+    Ny_TRASHCAN_BEGIN(v, mutnodeset_dealloc)
     mutnodeset_gc_clear(v);
     Py_TYPE(v)->tp_free((PyObject *)v);
-    Py_TRASHCAN_SAFE_END(v)
+    Ny_TRASHCAN_END(v)
 }
 
 size_t
@@ -606,7 +606,7 @@ NyNodeSet_setobj(NyNodeSetObject *v, PyObject *obj)
         if (r == -1)
             return -1;
         if (!r) {
-            Py_SIZE(v)++;
+            Py_SET_SIZE(v, Py_SIZE(v) + 1);
             if (v->flags & NS_HOLDOBJECTS) {
                 Py_INCREF(obj);
             }
@@ -647,7 +647,7 @@ NyNodeSet_clrobj(NyNodeSetObject *v, PyObject *obj)
         if (r == -1)
             return -1;
         if (r) {
-            Py_SIZE(v)--;
+            Py_SET_SIZE(v, Py_SIZE(v) - 1);
             if (v->flags & NS_HOLDOBJECTS) {
                 Py_DECREF(obj);
             }
@@ -752,7 +752,7 @@ nodeset_pop(NyNodeSetObject *v, PyObject *argnotused)
         NyBit bitno = NyMutBitSet_pop((NyMutBitSetObject *)v->u.bitset, 0);
         if (bitno == -1 && PyErr_Occurred())
             return 0;
-        Py_SIZE(v)--;
+        Py_SET_SIZE(v, Py_SIZE(v) - 1);
         return nodeset_bitno_to_obj(bitno);
     }
 }


Test patch:
diff --git a/docs/test_guppy.py b/docs/test_guppy.py
index 48c31d8..cb0fcc7 100644
--- a/docs/test_guppy.py
+++ b/docs/test_guppy.py
@@ -1,5 +1,5 @@
 # Tests generated by: guppy.gsl.Tester
-# Date: Sat Jan 23 02:08:08 2021
+# Date: Sat May 13 06:37:09 2023
 class Tester:
     tests = {}
     def test_guppy(self, arg):
diff --git a/docs/test_heapy.py b/docs/test_heapy.py
index 549d285..ed4b2e8 100644
--- a/docs/test_heapy.py
+++ b/docs/test_heapy.py
@@ -1,5 +1,5 @@
 # Tests generated by: guppy.gsl.Tester
-# Date: Sat Jan 23 02:08:08 2021
+# Date: Sat May 13 06:37:09 2023
 class Tester:
     tests = {}
     def get_ex_1(self):
diff --git a/docs/test_heapyc.py b/docs/test_heapyc.py
index eb8addd..aa35b1f 100644
--- a/docs/test_heapyc.py
+++ b/docs/test_heapyc.py
@@ -1,5 +1,5 @@
 # Tests generated by: guppy.gsl.Tester
-# Date: Sat Jan 23 02:08:08 2021
+# Date: Sat May 13 06:37:08 2023
 class Tester:
     tests = {}
     def get_ex_1(self):
diff --git a/guppy/heapy/test/test_ER.py b/guppy/heapy/test/test_ER.py
index 06c876e..cc8a9cf 100644
--- a/guppy/heapy/test/test_ER.py
+++ b/guppy/heapy/test/test_ER.py
@@ -232,8 +232,7 @@ class C:
             hp = self.heapy.Use
             hp.reprefix = 'hp.'
 
-            import sys
-            s = hp.iso(C.__dict__, C, c, c.__dict__, d, sys)
+            s = hp.iso(C.__dict__, C, c, c.__dict__, d, inspect)
 
             for pre in (
                 'Unity',
diff --git a/guppy/heapy/test/test_Path.py b/guppy/heapy/test/test_Path.py
index cf1a543..8d56294 100644
--- a/guppy/heapy/test/test_Path.py
+++ b/guppy/heapy/test/test_Path.py
@@ -67,8 +67,12 @@ def f():
         # xxx brittle test but catches a bug
         self.chkpath(co, 3, '%s.co_consts[1]')
         # commented in notes Sep 27 2004
-        relAttr = ('co_code', 'co_consts', 'co_names', 'co_varnames',
-                   'co_freevars', 'co_cellvars', 'co_filename', 'co_name')
+        relAttr = ('co_code', 'co_consts', 'co_names',
+                   'co_filename', 'co_name')
+        if self.version_info < (3, 11):
+            relAttr += ('co_varnames', 'co_freevars', 'co_cellvars')
+        else:
+            relAttr += ('co_exceptiontable', 'co_qualname')
         if self.version_info >= (3, 10):
             relAttr += ('co_linetable',)
         else:
@@ -325,9 +329,13 @@ def test_1(self):
             1/0
         except ZeroDivisionError:
             exc_type, exc_value, exc_traceback = sys.exc_info()
-            for name in 'exc_type', 'exc_value', 'exc_traceback':
-                rel = str(self.relation(root, eval(name)))
-                self.asis(eval(rel % 'root'), eval(name))
+            if sys.version_info >= (3, 11):
+                rel = str(self.relation(root, exc_value))
+                self.asis(eval(rel % 'root'), exc_value)
+            else:
+                for name in 'exc_type', 'exc_value', 'exc_traceback':
+                    rel = str(self.relation(root, eval(name)))
+                    self.asis(eval(rel % 'root'), eval(name))
 
             # There are more, untested, attributes, but the code is farily regular...
             # More complication is to do with frames which I concentrate on for now.
@@ -360,7 +368,7 @@ def task(self):
                 1/0
             except ZeroDivisionError:
                 exc_type, exc_value, exc_traceback = sys.exc_info()
-                self.exc_traceback = exc_traceback
+                self.exc_value = exc_value
                 self.sync = 1
                 while self.sync:
                     pass
@@ -370,9 +378,9 @@ def task(self):
         _thread.start_new_thread(task, (self,))
         while not self.sync:
             pass
-        exc_traceback = self.exc_traceback
-        rel = str(self.relation(root, exc_traceback))
-        self.asis(eval(rel % 'root'), exc_traceback)
+        exc_value = self.exc_value
+        rel = str(self.relation(root, exc_value))
+        self.asis(eval(rel % 'root'), exc_value)
         self.sync = 0
         while not self.sync:
             pass
@@ -765,7 +773,11 @@ def str_address(x): return '<address>'
         b = list(it)
         self.aseq(str(a), str(b))
 
-        self.aseq(o.getvalue(), """\
+        # The sort order is based on the source set's byid partition (see
+        # Path.PathsIter.reset), which sorts based on the size, then render
+        # (see Part.IdentityPartition.__init__)
+        if sys.getsizeof(y) > sys.getsizeof(ob):
+            self.aseq(o.getvalue(), """\
  0: hpy().Root.i0_sysdict
  0: Src.i0_modules['sys'].__dict__
  0: hpy().Root.i0_sysdict
@@ -781,6 +793,23 @@ def str_address(x): return '<address>'
  0: <1 list: <address>*1>[0]
  1: <1 __main__.O: <address>>.x
 """.replace('__main__', self.__module__))
+        else:
+            self.aseq(o.getvalue(), """\
+ 0: hpy().Root.i0_sysdict
+ 0: Src.i0_modules['sys'].__dict__
+ 0: hpy().Root.i0_sysdict
+ 0: hpy().Root.i0_sysdict
+ 0: Src[0][0][0]
+ 0: Src[0][0][0]
+ 0: Src[0]
+ 0: Src.x
+ 0: <1 list: <address>*1>[0]
+ 0: <1 list: <address>*1>[0]
+ 0: <1 __main__.O: <address>>.x
+ 1: <1 list: <address>*1>[0]
+ 0: <1 __main__.O: <address>>.x
+ 1: <1 list: <address>*1>[0]
+""".replace('__main__', self.__module__))
 
     def test_2(self):
         # To assist interactivity,
diff --git a/guppy/heapy/test/test_RefPat.py b/guppy/heapy/test/test_RefPat.py
index 86513aa..4658f4f 100644
--- a/guppy/heapy/test/test_RefPat.py
+++ b/guppy/heapy/test/test_RefPat.py
@@ -421,8 +421,13 @@ class A:
         gc.collect()
         rp = self.rp(dst, src, depth=10)
         rp.mod.View._is_clear_drg_enabled = 0  # Note Apr 19 2005
-        self.asis(rp.a.theone, b)
-        self.asis(rp.b.theone, a.__dict__)
+
+        if sys.getsizeof(b) > sys.getsizeof(a.__dict__):
+            self.asis(rp.a.theone, b)
+            self.asis(rp.b.theone, a.__dict__)
+        else:
+            self.asis(rp.a.theone, a.__dict__)
+            self.asis(rp.b.theone, b)
 
         # Test that the dict is eventually automatically removed from dictowners -
         # First test that dictowners is nonzero